trace: add "-trace help"
[qemu.git] / hw / ipmi / ipmi_bmc_sim.c
blobdcdab035d6e35cf3a6ff6c53106e4dba3b345cf8
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 "qemu/timer.h"
27 #include "hw/ipmi/ipmi.h"
28 #include "qemu/error-report.h"
30 #define IPMI_NETFN_CHASSIS 0x00
31 #define IPMI_NETFN_CHASSIS_MAXCMD 0x03
33 #define IPMI_CMD_GET_CHASSIS_CAPABILITIES 0x00
34 #define IPMI_CMD_GET_CHASSIS_STATUS 0x01
35 #define IPMI_CMD_CHASSIS_CONTROL 0x02
37 #define IPMI_NETFN_SENSOR_EVENT 0x04
38 #define IPMI_NETFN_SENSOR_EVENT_MAXCMD 0x2e
40 #define IPMI_CMD_SET_SENSOR_EVT_ENABLE 0x28
41 #define IPMI_CMD_GET_SENSOR_EVT_ENABLE 0x29
42 #define IPMI_CMD_REARM_SENSOR_EVTS 0x2a
43 #define IPMI_CMD_GET_SENSOR_EVT_STATUS 0x2b
44 #define IPMI_CMD_GET_SENSOR_READING 0x2d
46 /* #define IPMI_NETFN_APP 0x06 In ipmi.h */
47 #define IPMI_NETFN_APP_MAXCMD 0x36
49 #define IPMI_CMD_GET_DEVICE_ID 0x01
50 #define IPMI_CMD_COLD_RESET 0x02
51 #define IPMI_CMD_WARM_RESET 0x03
52 #define IPMI_CMD_RESET_WATCHDOG_TIMER 0x22
53 #define IPMI_CMD_SET_WATCHDOG_TIMER 0x24
54 #define IPMI_CMD_GET_WATCHDOG_TIMER 0x25
55 #define IPMI_CMD_SET_BMC_GLOBAL_ENABLES 0x2e
56 #define IPMI_CMD_GET_BMC_GLOBAL_ENABLES 0x2f
57 #define IPMI_CMD_CLR_MSG_FLAGS 0x30
58 #define IPMI_CMD_GET_MSG_FLAGS 0x31
59 #define IPMI_CMD_GET_MSG 0x33
60 #define IPMI_CMD_SEND_MSG 0x34
61 #define IPMI_CMD_READ_EVT_MSG_BUF 0x35
63 #define IPMI_NETFN_STORAGE 0x0a
64 #define IPMI_NETFN_STORAGE_MAXCMD 0x4a
66 #define IPMI_CMD_GET_SDR_REP_INFO 0x20
67 #define IPMI_CMD_GET_SDR_REP_ALLOC_INFO 0x21
68 #define IPMI_CMD_RESERVE_SDR_REP 0x22
69 #define IPMI_CMD_GET_SDR 0x23
70 #define IPMI_CMD_ADD_SDR 0x24
71 #define IPMI_CMD_PARTIAL_ADD_SDR 0x25
72 #define IPMI_CMD_DELETE_SDR 0x26
73 #define IPMI_CMD_CLEAR_SDR_REP 0x27
74 #define IPMI_CMD_GET_SDR_REP_TIME 0x28
75 #define IPMI_CMD_SET_SDR_REP_TIME 0x29
76 #define IPMI_CMD_ENTER_SDR_REP_UPD_MODE 0x2A
77 #define IPMI_CMD_EXIT_SDR_REP_UPD_MODE 0x2B
78 #define IPMI_CMD_RUN_INIT_AGENT 0x2C
79 #define IPMI_CMD_GET_SEL_INFO 0x40
80 #define IPMI_CMD_GET_SEL_ALLOC_INFO 0x41
81 #define IPMI_CMD_RESERVE_SEL 0x42
82 #define IPMI_CMD_GET_SEL_ENTRY 0x43
83 #define IPMI_CMD_ADD_SEL_ENTRY 0x44
84 #define IPMI_CMD_PARTIAL_ADD_SEL_ENTRY 0x45
85 #define IPMI_CMD_DELETE_SEL_ENTRY 0x46
86 #define IPMI_CMD_CLEAR_SEL 0x47
87 #define IPMI_CMD_GET_SEL_TIME 0x48
88 #define IPMI_CMD_SET_SEL_TIME 0x49
91 /* Same as a timespec struct. */
92 struct ipmi_time {
93 long tv_sec;
94 long tv_nsec;
97 #define MAX_SEL_SIZE 128
99 typedef struct IPMISel {
100 uint8_t sel[MAX_SEL_SIZE][16];
101 unsigned int next_free;
102 long time_offset;
103 uint16_t reservation;
104 uint8_t last_addition[4];
105 uint8_t last_clear[4];
106 uint8_t overflow;
107 } IPMISel;
109 #define MAX_SDR_SIZE 16384
111 typedef struct IPMISdr {
112 uint8_t sdr[MAX_SDR_SIZE];
113 unsigned int next_free;
114 uint16_t next_rec_id;
115 uint16_t reservation;
116 uint8_t last_addition[4];
117 uint8_t last_clear[4];
118 uint8_t overflow;
119 } IPMISdr;
121 typedef struct IPMISensor {
122 uint8_t status;
123 uint8_t reading;
124 uint16_t states_suppt;
125 uint16_t assert_suppt;
126 uint16_t deassert_suppt;
127 uint16_t states;
128 uint16_t assert_states;
129 uint16_t deassert_states;
130 uint16_t assert_enable;
131 uint16_t deassert_enable;
132 uint8_t sensor_type;
133 uint8_t evt_reading_type_code;
134 } IPMISensor;
135 #define IPMI_SENSOR_GET_PRESENT(s) ((s)->status & 0x01)
136 #define IPMI_SENSOR_SET_PRESENT(s, v) ((s)->status = (s->status & ~0x01) | \
137 !!(v))
138 #define IPMI_SENSOR_GET_SCAN_ON(s) ((s)->status & 0x40)
139 #define IPMI_SENSOR_SET_SCAN_ON(s, v) ((s)->status = (s->status & ~0x40) | \
140 ((!!(v)) << 6))
141 #define IPMI_SENSOR_GET_EVENTS_ON(s) ((s)->status & 0x80)
142 #define IPMI_SENSOR_SET_EVENTS_ON(s, v) ((s)->status = (s->status & ~0x80) | \
143 ((!!(v)) << 7))
144 #define IPMI_SENSOR_GET_RET_STATUS(s) ((s)->status & 0xc0)
145 #define IPMI_SENSOR_SET_RET_STATUS(s, v) ((s)->status = (s->status & ~0xc0) | \
146 (v & 0xc0))
147 #define IPMI_SENSOR_IS_DISCRETE(s) ((s)->evt_reading_type_code != 1)
149 #define MAX_SENSORS 20
150 #define IPMI_WATCHDOG_SENSOR 0
152 typedef struct IPMIBmcSim IPMIBmcSim;
154 #define MAX_NETFNS 64
155 typedef void (*IPMICmdHandler)(IPMIBmcSim *s,
156 uint8_t *cmd, unsigned int cmd_len,
157 uint8_t *rsp, unsigned int *rsp_len,
158 unsigned int max_rsp_len);
159 typedef struct IPMINetfn {
160 unsigned int cmd_nums;
161 const IPMICmdHandler *cmd_handlers;
162 } IPMINetfn;
164 typedef struct IPMIRcvBufEntry {
165 QTAILQ_ENTRY(IPMIRcvBufEntry) entry;
166 uint8_t len;
167 uint8_t buf[MAX_IPMI_MSG_SIZE];
168 } IPMIRcvBufEntry;
170 #define TYPE_IPMI_BMC_SIMULATOR "ipmi-bmc-sim"
171 #define IPMI_BMC_SIMULATOR(obj) OBJECT_CHECK(IPMIBmcSim, (obj), \
172 TYPE_IPMI_BMC_SIMULATOR)
173 struct IPMIBmcSim {
174 IPMIBmc parent;
176 QEMUTimer *timer;
178 uint8_t bmc_global_enables;
179 uint8_t msg_flags;
181 bool watchdog_initialized;
182 uint8_t watchdog_use;
183 uint8_t watchdog_action;
184 uint8_t watchdog_pretimeout; /* In seconds */
185 bool watchdog_expired;
186 uint16_t watchdog_timeout; /* in 100's of milliseconds */
188 bool watchdog_running;
189 bool watchdog_preaction_ran;
190 int64_t watchdog_expiry;
192 uint8_t device_id;
193 uint8_t ipmi_version;
194 uint8_t device_rev;
195 uint8_t fwrev1;
196 uint8_t fwrev2;
197 uint8_t mfg_id[3];
198 uint8_t product_id[2];
200 IPMISel sel;
201 IPMISdr sdr;
202 IPMISensor sensors[MAX_SENSORS];
204 /* Odd netfns are for responses, so we only need the even ones. */
205 const IPMINetfn *netfns[MAX_NETFNS / 2];
207 QemuMutex lock;
208 /* We allow one event in the buffer */
209 uint8_t evtbuf[16];
211 QTAILQ_HEAD(, IPMIRcvBufEntry) rcvbufs;
214 #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK (1 << 3)
215 #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL (1 << 1)
216 #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE (1 << 0)
217 #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(s) \
218 (IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK & (s)->msg_flags)
219 #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(s) \
220 (IPMI_BMC_MSG_FLAG_EVT_BUF_FULL & (s)->msg_flags)
221 #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(s) \
222 (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE & (s)->msg_flags)
224 #define IPMI_BMC_RCV_MSG_QUEUE_INT_BIT 0
225 #define IPMI_BMC_EVBUF_FULL_INT_BIT 1
226 #define IPMI_BMC_EVENT_MSG_BUF_BIT 2
227 #define IPMI_BMC_EVENT_LOG_BIT 3
228 #define IPMI_BMC_MSG_INTS_ON(s) ((s)->bmc_global_enables & \
229 (1 << IPMI_BMC_RCV_MSG_QUEUE_INT_BIT))
230 #define IPMI_BMC_EVBUF_FULL_INT_ENABLED(s) ((s)->bmc_global_enables & \
231 (1 << IPMI_BMC_EVBUF_FULL_INT_BIT))
232 #define IPMI_BMC_EVENT_LOG_ENABLED(s) ((s)->bmc_global_enables & \
233 (1 << IPMI_BMC_EVENT_LOG_BIT))
234 #define IPMI_BMC_EVENT_MSG_BUF_ENABLED(s) ((s)->bmc_global_enables & \
235 (1 << IPMI_BMC_EVENT_MSG_BUF_BIT))
237 #define IPMI_BMC_WATCHDOG_USE_MASK 0xc7
238 #define IPMI_BMC_WATCHDOG_ACTION_MASK 0x77
239 #define IPMI_BMC_WATCHDOG_GET_USE(s) ((s)->watchdog_use & 0x7)
240 #define IPMI_BMC_WATCHDOG_GET_DONT_LOG(s) (((s)->watchdog_use >> 7) & 0x1)
241 #define IPMI_BMC_WATCHDOG_GET_DONT_STOP(s) (((s)->watchdog_use >> 6) & 0x1)
242 #define IPMI_BMC_WATCHDOG_GET_PRE_ACTION(s) (((s)->watchdog_action >> 4) & 0x7)
243 #define IPMI_BMC_WATCHDOG_PRE_NONE 0
244 #define IPMI_BMC_WATCHDOG_PRE_SMI 1
245 #define IPMI_BMC_WATCHDOG_PRE_NMI 2
246 #define IPMI_BMC_WATCHDOG_PRE_MSG_INT 3
247 #define IPMI_BMC_WATCHDOG_GET_ACTION(s) ((s)->watchdog_action & 0x7)
248 #define IPMI_BMC_WATCHDOG_ACTION_NONE 0
249 #define IPMI_BMC_WATCHDOG_ACTION_RESET 1
250 #define IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN 2
251 #define IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE 3
254 /* Add a byte to the response. */
255 #define IPMI_ADD_RSP_DATA(b) \
256 do { \
257 if (*rsp_len >= max_rsp_len) { \
258 rsp[2] = IPMI_CC_REQUEST_DATA_TRUNCATED; \
259 goto out; \
261 rsp[(*rsp_len)++] = (b); \
262 } while (0)
264 /* Verify that the received command is a certain length. */
265 #define IPMI_CHECK_CMD_LEN(l) \
266 if (cmd_len < l) { \
267 rsp[2] = IPMI_CC_REQUEST_DATA_LENGTH_INVALID; \
268 goto out; \
271 /* Check that the reservation in the command is valid. */
272 #define IPMI_CHECK_RESERVATION(off, r) \
273 do { \
274 if ((cmd[off] | (cmd[off + 1] << 8)) != r) { \
275 rsp[2] = IPMI_CC_INVALID_RESERVATION; \
276 goto out; \
278 } while (0)
281 static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs);
283 static void ipmi_gettime(struct ipmi_time *time)
285 int64_t stime;
287 stime = qemu_clock_get_ns(QEMU_CLOCK_HOST);
288 time->tv_sec = stime / 1000000000LL;
289 time->tv_nsec = stime % 1000000000LL;
292 static int64_t ipmi_getmonotime(void)
294 return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
297 static void ipmi_timeout(void *opaque)
299 IPMIBmcSim *ibs = opaque;
301 ipmi_sim_handle_timeout(ibs);
304 static void set_timestamp(IPMIBmcSim *ibs, uint8_t *ts)
306 unsigned int val;
307 struct ipmi_time now;
309 ipmi_gettime(&now);
310 val = now.tv_sec + ibs->sel.time_offset;
311 ts[0] = val & 0xff;
312 ts[1] = (val >> 8) & 0xff;
313 ts[2] = (val >> 16) & 0xff;
314 ts[3] = (val >> 24) & 0xff;
317 static void sdr_inc_reservation(IPMISdr *sdr)
319 sdr->reservation++;
320 if (sdr->reservation == 0) {
321 sdr->reservation = 1;
325 static int sdr_add_entry(IPMIBmcSim *ibs, const uint8_t *entry,
326 unsigned int len, uint16_t *recid)
328 if ((len < 5) || (len > 255)) {
329 return 1;
332 if (entry[4] != len - 5) {
333 return 1;
336 if (ibs->sdr.next_free + len > MAX_SDR_SIZE) {
337 ibs->sdr.overflow = 1;
338 return 1;
341 memcpy(ibs->sdr.sdr + ibs->sdr.next_free, entry, len);
342 ibs->sdr.sdr[ibs->sdr.next_free] = ibs->sdr.next_rec_id & 0xff;
343 ibs->sdr.sdr[ibs->sdr.next_free+1] = (ibs->sdr.next_rec_id >> 8) & 0xff;
344 ibs->sdr.sdr[ibs->sdr.next_free+2] = 0x51; /* Conform to IPMI 1.5 spec */
346 if (recid) {
347 *recid = ibs->sdr.next_rec_id;
349 ibs->sdr.next_rec_id++;
350 set_timestamp(ibs, ibs->sdr.last_addition);
351 ibs->sdr.next_free += len;
352 sdr_inc_reservation(&ibs->sdr);
353 return 0;
356 static int sdr_find_entry(IPMISdr *sdr, uint16_t recid,
357 unsigned int *retpos, uint16_t *nextrec)
359 unsigned int pos = *retpos;
361 while (pos < sdr->next_free) {
362 uint16_t trec = sdr->sdr[pos] | (sdr->sdr[pos + 1] << 8);
363 unsigned int nextpos = pos + sdr->sdr[pos + 4];
365 if (trec == recid) {
366 if (nextrec) {
367 if (nextpos >= sdr->next_free) {
368 *nextrec = 0xffff;
369 } else {
370 *nextrec = (sdr->sdr[nextpos] |
371 (sdr->sdr[nextpos + 1] << 8));
374 *retpos = pos;
375 return 0;
377 pos = nextpos;
379 return 1;
382 static void sel_inc_reservation(IPMISel *sel)
384 sel->reservation++;
385 if (sel->reservation == 0) {
386 sel->reservation = 1;
390 /* Returns 1 if the SEL is full and can't hold the event. */
391 static int sel_add_event(IPMIBmcSim *ibs, uint8_t *event)
393 event[0] = 0xff;
394 event[1] = 0xff;
395 set_timestamp(ibs, event + 3);
396 if (ibs->sel.next_free == MAX_SEL_SIZE) {
397 ibs->sel.overflow = 1;
398 return 1;
400 event[0] = ibs->sel.next_free & 0xff;
401 event[1] = (ibs->sel.next_free >> 8) & 0xff;
402 memcpy(ibs->sel.last_addition, event + 3, 4);
403 memcpy(ibs->sel.sel[ibs->sel.next_free], event, 16);
404 ibs->sel.next_free++;
405 sel_inc_reservation(&ibs->sel);
406 return 0;
409 static int attn_set(IPMIBmcSim *ibs)
411 return IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs)
412 || IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs)
413 || IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs);
416 static int attn_irq_enabled(IPMIBmcSim *ibs)
418 return (IPMI_BMC_MSG_INTS_ON(ibs) && IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs))
419 || (IPMI_BMC_EVBUF_FULL_INT_ENABLED(ibs) &&
420 IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs));
423 static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert,
424 uint8_t evd1, uint8_t evd2, uint8_t evd3)
426 IPMIInterface *s = ibs->parent.intf;
427 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
428 uint8_t evt[16];
429 IPMISensor *sens = ibs->sensors + sens_num;
431 if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) {
432 return;
434 if (!IPMI_SENSOR_GET_EVENTS_ON(sens)) {
435 return;
438 evt[2] = 0x2; /* System event record */
439 evt[7] = ibs->parent.slave_addr;
440 evt[8] = 0;
441 evt[9] = 0x04; /* Format version */
442 evt[10] = sens->sensor_type;
443 evt[11] = sens_num;
444 evt[12] = sens->evt_reading_type_code | (!!deassert << 7);
445 evt[13] = evd1;
446 evt[14] = evd2;
447 evt[15] = evd3;
449 if (IPMI_BMC_EVENT_LOG_ENABLED(ibs)) {
450 sel_add_event(ibs, evt);
453 if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) {
454 goto out;
457 memcpy(ibs->evtbuf, evt, 16);
458 ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
459 k->set_atn(s, 1, attn_irq_enabled(ibs));
460 out:
461 return;
464 static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor,
465 unsigned int bit, unsigned int val,
466 uint8_t evd1, uint8_t evd2, uint8_t evd3)
468 IPMISensor *sens;
469 uint16_t mask;
471 if (sensor >= MAX_SENSORS) {
472 return;
474 if (bit >= 16) {
475 return;
478 mask = (1 << bit);
479 sens = ibs->sensors + sensor;
480 if (val) {
481 sens->states |= mask & sens->states_suppt;
482 if (sens->assert_states & mask) {
483 return; /* Already asserted */
485 sens->assert_states |= mask & sens->assert_suppt;
486 if (sens->assert_enable & mask & sens->assert_states) {
487 /* Send an event on assert */
488 gen_event(ibs, sensor, 0, evd1, evd2, evd3);
490 } else {
491 sens->states &= ~(mask & sens->states_suppt);
492 if (sens->deassert_states & mask) {
493 return; /* Already deasserted */
495 sens->deassert_states |= mask & sens->deassert_suppt;
496 if (sens->deassert_enable & mask & sens->deassert_states) {
497 /* Send an event on deassert */
498 gen_event(ibs, sensor, 1, evd1, evd2, evd3);
503 static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s)
505 unsigned int i, pos;
506 IPMISensor *sens;
508 for (i = 0; i < MAX_SENSORS; i++) {
509 memset(s->sensors + i, 0, sizeof(*sens));
512 pos = 0;
513 for (i = 0; !sdr_find_entry(&s->sdr, i, &pos, NULL); i++) {
514 uint8_t *sdr = s->sdr.sdr + pos;
515 unsigned int len = sdr[4];
517 if (len < 20) {
518 continue;
520 if ((sdr[3] < 1) || (sdr[3] > 2)) {
521 continue; /* Not a sensor SDR we set from */
524 if (sdr[7] > MAX_SENSORS) {
525 continue;
527 sens = s->sensors + sdr[7];
529 IPMI_SENSOR_SET_PRESENT(sens, 1);
530 IPMI_SENSOR_SET_SCAN_ON(sens, (sdr[10] >> 6) & 1);
531 IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr[10] >> 5) & 1);
532 sens->assert_suppt = sdr[14] | (sdr[15] << 8);
533 sens->deassert_suppt = sdr[16] | (sdr[17] << 8);
534 sens->states_suppt = sdr[18] | (sdr[19] << 8);
535 sens->sensor_type = sdr[12];
536 sens->evt_reading_type_code = sdr[13] & 0x7f;
538 /* Enable all the events that are supported. */
539 sens->assert_enable = sens->assert_suppt;
540 sens->deassert_enable = sens->deassert_suppt;
544 static int ipmi_register_netfn(IPMIBmcSim *s, unsigned int netfn,
545 const IPMINetfn *netfnd)
547 if ((netfn & 1) || (netfn > MAX_NETFNS) || (s->netfns[netfn / 2])) {
548 return -1;
550 s->netfns[netfn / 2] = netfnd;
551 return 0;
554 static void next_timeout(IPMIBmcSim *ibs)
556 int64_t next;
557 if (ibs->watchdog_running) {
558 next = ibs->watchdog_expiry;
559 } else {
560 /* Wait a minute */
561 next = ipmi_getmonotime() + 60 * 1000000000LL;
563 timer_mod_ns(ibs->timer, next);
566 static void ipmi_sim_handle_command(IPMIBmc *b,
567 uint8_t *cmd, unsigned int cmd_len,
568 unsigned int max_cmd_len,
569 uint8_t msg_id)
571 IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
572 IPMIInterface *s = ibs->parent.intf;
573 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
574 unsigned int netfn;
575 uint8_t rsp[MAX_IPMI_MSG_SIZE];
576 unsigned int rsp_len_holder = 0;
577 unsigned int *rsp_len = &rsp_len_holder;
578 unsigned int max_rsp_len = sizeof(rsp);
580 /* Set up the response, set the low bit of NETFN. */
581 /* Note that max_rsp_len must be at least 3 */
582 IPMI_ADD_RSP_DATA(cmd[0] | 0x04);
583 IPMI_ADD_RSP_DATA(cmd[1]);
584 IPMI_ADD_RSP_DATA(0); /* Assume success */
586 /* If it's too short or it was truncated, return an error. */
587 if (cmd_len < 2) {
588 rsp[2] = IPMI_CC_REQUEST_DATA_LENGTH_INVALID;
589 goto out;
591 if (cmd_len > max_cmd_len) {
592 rsp[2] = IPMI_CC_REQUEST_DATA_TRUNCATED;
593 goto out;
596 if ((cmd[0] & 0x03) != 0) {
597 /* Only have stuff on LUN 0 */
598 rsp[2] = IPMI_CC_COMMAND_INVALID_FOR_LUN;
599 goto out;
602 netfn = cmd[0] >> 2;
604 /* Odd netfns are not valid, make sure the command is registered */
605 if ((netfn & 1) || !ibs->netfns[netfn / 2] ||
606 (cmd[1] >= ibs->netfns[netfn / 2]->cmd_nums) ||
607 (!ibs->netfns[netfn / 2]->cmd_handlers[cmd[1]])) {
608 rsp[2] = IPMI_CC_INVALID_CMD;
609 goto out;
612 ibs->netfns[netfn / 2]->cmd_handlers[cmd[1]](ibs, cmd, cmd_len, rsp, rsp_len,
613 max_rsp_len);
615 out:
616 k->handle_rsp(s, msg_id, rsp, *rsp_len);
618 next_timeout(ibs);
621 static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs)
623 IPMIInterface *s = ibs->parent.intf;
624 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
626 if (!ibs->watchdog_running) {
627 goto out;
630 if (!ibs->watchdog_preaction_ran) {
631 switch (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs)) {
632 case IPMI_BMC_WATCHDOG_PRE_NMI:
633 ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
634 k->do_hw_op(s, IPMI_SEND_NMI, 0);
635 sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
636 0xc8, (2 << 4) | 0xf, 0xff);
637 break;
639 case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
640 ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
641 k->set_atn(s, 1, attn_irq_enabled(ibs));
642 sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
643 0xc8, (3 << 4) | 0xf, 0xff);
644 break;
646 default:
647 goto do_full_expiry;
650 ibs->watchdog_preaction_ran = 1;
651 /* Issued the pretimeout, do the rest of the timeout now. */
652 ibs->watchdog_expiry = ipmi_getmonotime();
653 ibs->watchdog_expiry += ibs->watchdog_pretimeout * 1000000000LL;
654 goto out;
657 do_full_expiry:
658 ibs->watchdog_running = 0; /* Stop the watchdog on a timeout */
659 ibs->watchdog_expired |= (1 << IPMI_BMC_WATCHDOG_GET_USE(ibs));
660 switch (IPMI_BMC_WATCHDOG_GET_ACTION(ibs)) {
661 case IPMI_BMC_WATCHDOG_ACTION_NONE:
662 sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 0, 1,
663 0xc0, ibs->watchdog_use & 0xf, 0xff);
664 break;
666 case IPMI_BMC_WATCHDOG_ACTION_RESET:
667 sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 1, 1,
668 0xc1, ibs->watchdog_use & 0xf, 0xff);
669 k->do_hw_op(s, IPMI_RESET_CHASSIS, 0);
670 break;
672 case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
673 sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
674 0xc2, ibs->watchdog_use & 0xf, 0xff);
675 k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0);
676 break;
678 case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
679 sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
680 0xc3, ibs->watchdog_use & 0xf, 0xff);
681 k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0);
682 break;
685 out:
686 next_timeout(ibs);
689 static void chassis_capabilities(IPMIBmcSim *ibs,
690 uint8_t *cmd, unsigned int cmd_len,
691 uint8_t *rsp, unsigned int *rsp_len,
692 unsigned int max_rsp_len)
694 IPMI_ADD_RSP_DATA(0);
695 IPMI_ADD_RSP_DATA(ibs->parent.slave_addr);
696 IPMI_ADD_RSP_DATA(ibs->parent.slave_addr);
697 IPMI_ADD_RSP_DATA(ibs->parent.slave_addr);
698 IPMI_ADD_RSP_DATA(ibs->parent.slave_addr);
699 out:
700 return;
703 static void chassis_status(IPMIBmcSim *ibs,
704 uint8_t *cmd, unsigned int cmd_len,
705 uint8_t *rsp, unsigned int *rsp_len,
706 unsigned int max_rsp_len)
708 IPMI_ADD_RSP_DATA(0x61); /* Unknown power restore, power is on */
709 IPMI_ADD_RSP_DATA(0);
710 IPMI_ADD_RSP_DATA(0);
711 IPMI_ADD_RSP_DATA(0);
712 out:
713 return;
716 static void chassis_control(IPMIBmcSim *ibs,
717 uint8_t *cmd, unsigned int cmd_len,
718 uint8_t *rsp, unsigned int *rsp_len,
719 unsigned int max_rsp_len)
721 IPMIInterface *s = ibs->parent.intf;
722 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
724 IPMI_CHECK_CMD_LEN(3);
725 switch (cmd[2] & 0xf) {
726 case 0: /* power down */
727 rsp[2] = k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0);
728 break;
729 case 1: /* power up */
730 rsp[2] = k->do_hw_op(s, IPMI_POWERON_CHASSIS, 0);
731 break;
732 case 2: /* power cycle */
733 rsp[2] = k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0);
734 break;
735 case 3: /* hard reset */
736 rsp[2] = k->do_hw_op(s, IPMI_RESET_CHASSIS, 0);
737 break;
738 case 4: /* pulse diagnostic interrupt */
739 rsp[2] = k->do_hw_op(s, IPMI_PULSE_DIAG_IRQ, 0);
740 break;
741 case 5: /* soft shutdown via ACPI by overtemp emulation */
742 rsp[2] = k->do_hw_op(s,
743 IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 0);
744 break;
745 default:
746 rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
747 goto out;
749 out:
750 return;
753 static void get_device_id(IPMIBmcSim *ibs,
754 uint8_t *cmd, unsigned int cmd_len,
755 uint8_t *rsp, unsigned int *rsp_len,
756 unsigned int max_rsp_len)
758 IPMI_ADD_RSP_DATA(ibs->device_id);
759 IPMI_ADD_RSP_DATA(ibs->device_rev & 0xf);
760 IPMI_ADD_RSP_DATA(ibs->fwrev1 & 0x7f);
761 IPMI_ADD_RSP_DATA(ibs->fwrev2);
762 IPMI_ADD_RSP_DATA(ibs->ipmi_version);
763 IPMI_ADD_RSP_DATA(0x07); /* sensor, SDR, and SEL. */
764 IPMI_ADD_RSP_DATA(ibs->mfg_id[0]);
765 IPMI_ADD_RSP_DATA(ibs->mfg_id[1]);
766 IPMI_ADD_RSP_DATA(ibs->mfg_id[2]);
767 IPMI_ADD_RSP_DATA(ibs->product_id[0]);
768 IPMI_ADD_RSP_DATA(ibs->product_id[1]);
769 out:
770 return;
773 static void set_global_enables(IPMIBmcSim *ibs, uint8_t val)
775 IPMIInterface *s = ibs->parent.intf;
776 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
777 bool irqs_on;
779 ibs->bmc_global_enables = val;
781 irqs_on = val & (IPMI_BMC_EVBUF_FULL_INT_BIT |
782 IPMI_BMC_RCV_MSG_QUEUE_INT_BIT);
784 k->set_irq_enable(s, irqs_on);
787 static void cold_reset(IPMIBmcSim *ibs,
788 uint8_t *cmd, unsigned int cmd_len,
789 uint8_t *rsp, unsigned int *rsp_len,
790 unsigned int max_rsp_len)
792 IPMIInterface *s = ibs->parent.intf;
793 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
795 /* Disable all interrupts */
796 set_global_enables(ibs, 1 << IPMI_BMC_EVENT_LOG_BIT);
798 if (k->reset) {
799 k->reset(s, true);
803 static void warm_reset(IPMIBmcSim *ibs,
804 uint8_t *cmd, unsigned int cmd_len,
805 uint8_t *rsp, unsigned int *rsp_len,
806 unsigned int max_rsp_len)
808 IPMIInterface *s = ibs->parent.intf;
809 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
811 if (k->reset) {
812 k->reset(s, false);
816 static void set_bmc_global_enables(IPMIBmcSim *ibs,
817 uint8_t *cmd, unsigned int cmd_len,
818 uint8_t *rsp, unsigned int *rsp_len,
819 unsigned int max_rsp_len)
821 IPMI_CHECK_CMD_LEN(3);
822 set_global_enables(ibs, cmd[2]);
823 out:
824 return;
827 static void get_bmc_global_enables(IPMIBmcSim *ibs,
828 uint8_t *cmd, unsigned int cmd_len,
829 uint8_t *rsp, unsigned int *rsp_len,
830 unsigned int max_rsp_len)
832 IPMI_ADD_RSP_DATA(ibs->bmc_global_enables);
833 out:
834 return;
837 static void clr_msg_flags(IPMIBmcSim *ibs,
838 uint8_t *cmd, unsigned int cmd_len,
839 uint8_t *rsp, unsigned int *rsp_len,
840 unsigned int max_rsp_len)
842 IPMIInterface *s = ibs->parent.intf;
843 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
845 IPMI_CHECK_CMD_LEN(3);
846 ibs->msg_flags &= ~cmd[2];
847 k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
848 out:
849 return;
852 static void get_msg_flags(IPMIBmcSim *ibs,
853 uint8_t *cmd, unsigned int cmd_len,
854 uint8_t *rsp, unsigned int *rsp_len,
855 unsigned int max_rsp_len)
857 IPMI_ADD_RSP_DATA(ibs->msg_flags);
858 out:
859 return;
862 static void read_evt_msg_buf(IPMIBmcSim *ibs,
863 uint8_t *cmd, unsigned int cmd_len,
864 uint8_t *rsp, unsigned int *rsp_len,
865 unsigned int max_rsp_len)
867 IPMIInterface *s = ibs->parent.intf;
868 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
869 unsigned int i;
871 if (!(ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL)) {
872 rsp[2] = 0x80;
873 goto out;
875 for (i = 0; i < 16; i++) {
876 IPMI_ADD_RSP_DATA(ibs->evtbuf[i]);
878 ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
879 k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
880 out:
881 return;
884 static void get_msg(IPMIBmcSim *ibs,
885 uint8_t *cmd, unsigned int cmd_len,
886 uint8_t *rsp, unsigned int *rsp_len,
887 unsigned int max_rsp_len)
889 IPMIRcvBufEntry *msg;
891 qemu_mutex_lock(&ibs->lock);
892 if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
893 rsp[2] = 0x80; /* Queue empty */
894 goto out;
896 rsp[3] = 0; /* Channel 0 */
897 *rsp_len += 1;
898 msg = QTAILQ_FIRST(&ibs->rcvbufs);
899 memcpy(rsp + 4, msg->buf, msg->len);
900 *rsp_len += msg->len;
901 QTAILQ_REMOVE(&ibs->rcvbufs, msg, entry);
902 g_free(msg);
904 if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
905 IPMIInterface *s = ibs->parent.intf;
906 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
908 ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
909 k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
912 out:
913 qemu_mutex_unlock(&ibs->lock);
914 return;
917 static unsigned char
918 ipmb_checksum(unsigned char *data, int size, unsigned char csum)
920 for (; size > 0; size--, data++) {
921 csum += *data;
924 return -csum;
927 static void send_msg(IPMIBmcSim *ibs,
928 uint8_t *cmd, unsigned int cmd_len,
929 uint8_t *rsp, unsigned int *rsp_len,
930 unsigned int max_rsp_len)
932 IPMIInterface *s = ibs->parent.intf;
933 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
934 IPMIRcvBufEntry *msg;
935 uint8_t *buf;
936 uint8_t netfn, rqLun, rsLun, rqSeq;
938 IPMI_CHECK_CMD_LEN(3);
940 if (cmd[2] != 0) {
941 /* We only handle channel 0 with no options */
942 rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
943 goto out;
946 IPMI_CHECK_CMD_LEN(10);
947 if (cmd[3] != 0x40) {
948 /* We only emulate a MC at address 0x40. */
949 rsp[2] = 0x83; /* NAK on write */
950 goto out;
953 cmd += 3; /* Skip the header. */
954 cmd_len -= 3;
957 * At this point we "send" the message successfully. Any error will
958 * be returned in the response.
960 if (ipmb_checksum(cmd, cmd_len, 0) != 0 ||
961 cmd[3] != 0x20) { /* Improper response address */
962 goto out; /* No response */
965 netfn = cmd[1] >> 2;
966 rqLun = cmd[4] & 0x3;
967 rsLun = cmd[1] & 0x3;
968 rqSeq = cmd[4] >> 2;
970 if (rqLun != 2) {
971 /* We only support LUN 2 coming back to us. */
972 goto out;
975 msg = g_malloc(sizeof(*msg));
976 msg->buf[0] = ((netfn | 1) << 2) | rqLun; /* NetFN, and make a response */
977 msg->buf[1] = ipmb_checksum(msg->buf, 1, 0);
978 msg->buf[2] = cmd[0]; /* rsSA */
979 msg->buf[3] = (rqSeq << 2) | rsLun;
980 msg->buf[4] = cmd[5]; /* Cmd */
981 msg->buf[5] = 0; /* Completion Code */
982 msg->len = 6;
984 if ((cmd[1] >> 2) != IPMI_NETFN_APP || cmd[5] != IPMI_CMD_GET_DEVICE_ID) {
985 /* Not a command we handle. */
986 msg->buf[5] = IPMI_CC_INVALID_CMD;
987 goto end_msg;
990 buf = msg->buf + msg->len; /* After the CC */
991 buf[0] = 0;
992 buf[1] = 0;
993 buf[2] = 0;
994 buf[3] = 0;
995 buf[4] = 0x51;
996 buf[5] = 0;
997 buf[6] = 0;
998 buf[7] = 0;
999 buf[8] = 0;
1000 buf[9] = 0;
1001 buf[10] = 0;
1002 msg->len += 11;
1004 end_msg:
1005 msg->buf[msg->len] = ipmb_checksum(msg->buf, msg->len, 0);
1006 msg->len++;
1007 qemu_mutex_lock(&ibs->lock);
1008 QTAILQ_INSERT_TAIL(&ibs->rcvbufs, msg, entry);
1009 ibs->msg_flags |= IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
1010 k->set_atn(s, 1, attn_irq_enabled(ibs));
1011 qemu_mutex_unlock(&ibs->lock);
1013 out:
1014 return;
1017 static void do_watchdog_reset(IPMIBmcSim *ibs)
1019 if (IPMI_BMC_WATCHDOG_GET_ACTION(ibs) ==
1020 IPMI_BMC_WATCHDOG_ACTION_NONE) {
1021 ibs->watchdog_running = 0;
1022 return;
1024 ibs->watchdog_preaction_ran = 0;
1027 /* Timeout is in tenths of a second, offset is in seconds */
1028 ibs->watchdog_expiry = ipmi_getmonotime();
1029 ibs->watchdog_expiry += ibs->watchdog_timeout * 100000000LL;
1030 if (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs) != IPMI_BMC_WATCHDOG_PRE_NONE) {
1031 ibs->watchdog_expiry -= ibs->watchdog_pretimeout * 1000000000LL;
1033 ibs->watchdog_running = 1;
1036 static void reset_watchdog_timer(IPMIBmcSim *ibs,
1037 uint8_t *cmd, unsigned int cmd_len,
1038 uint8_t *rsp, unsigned int *rsp_len,
1039 unsigned int max_rsp_len)
1041 if (!ibs->watchdog_initialized) {
1042 rsp[2] = 0x80;
1043 goto out;
1045 do_watchdog_reset(ibs);
1046 out:
1047 return;
1050 static void set_watchdog_timer(IPMIBmcSim *ibs,
1051 uint8_t *cmd, unsigned int cmd_len,
1052 uint8_t *rsp, unsigned int *rsp_len,
1053 unsigned int max_rsp_len)
1055 IPMIInterface *s = ibs->parent.intf;
1056 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
1057 unsigned int val;
1059 IPMI_CHECK_CMD_LEN(8);
1060 val = cmd[2] & 0x7; /* Validate use */
1061 if (val == 0 || val > 5) {
1062 rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1063 goto out;
1065 val = cmd[3] & 0x7; /* Validate action */
1066 switch (val) {
1067 case IPMI_BMC_WATCHDOG_ACTION_NONE:
1068 break;
1070 case IPMI_BMC_WATCHDOG_ACTION_RESET:
1071 rsp[2] = k->do_hw_op(s, IPMI_RESET_CHASSIS, 1);
1072 break;
1074 case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
1075 rsp[2] = k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 1);
1076 break;
1078 case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
1079 rsp[2] = k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 1);
1080 break;
1082 default:
1083 rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1085 if (rsp[2]) {
1086 rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1087 goto out;
1090 val = (cmd[3] >> 4) & 0x7; /* Validate preaction */
1091 switch (val) {
1092 case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
1093 case IPMI_BMC_WATCHDOG_PRE_NONE:
1094 break;
1096 case IPMI_BMC_WATCHDOG_PRE_NMI:
1097 if (!k->do_hw_op(s, IPMI_SEND_NMI, 1)) {
1098 /* NMI not supported. */
1099 rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1100 goto out;
1102 default:
1103 /* We don't support PRE_SMI */
1104 rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1105 goto out;
1108 ibs->watchdog_initialized = 1;
1109 ibs->watchdog_use = cmd[2] & IPMI_BMC_WATCHDOG_USE_MASK;
1110 ibs->watchdog_action = cmd[3] & IPMI_BMC_WATCHDOG_ACTION_MASK;
1111 ibs->watchdog_pretimeout = cmd[4];
1112 ibs->watchdog_expired &= ~cmd[5];
1113 ibs->watchdog_timeout = cmd[6] | (((uint16_t) cmd[7]) << 8);
1114 if (ibs->watchdog_running & IPMI_BMC_WATCHDOG_GET_DONT_STOP(ibs)) {
1115 do_watchdog_reset(ibs);
1116 } else {
1117 ibs->watchdog_running = 0;
1119 out:
1120 return;
1123 static void get_watchdog_timer(IPMIBmcSim *ibs,
1124 uint8_t *cmd, unsigned int cmd_len,
1125 uint8_t *rsp, unsigned int *rsp_len,
1126 unsigned int max_rsp_len)
1128 IPMI_ADD_RSP_DATA(ibs->watchdog_use);
1129 IPMI_ADD_RSP_DATA(ibs->watchdog_action);
1130 IPMI_ADD_RSP_DATA(ibs->watchdog_pretimeout);
1131 IPMI_ADD_RSP_DATA(ibs->watchdog_expired);
1132 if (ibs->watchdog_running) {
1133 long timeout;
1134 timeout = ((ibs->watchdog_expiry - ipmi_getmonotime() + 50000000)
1135 / 100000000);
1136 IPMI_ADD_RSP_DATA(timeout & 0xff);
1137 IPMI_ADD_RSP_DATA((timeout >> 8) & 0xff);
1138 } else {
1139 IPMI_ADD_RSP_DATA(0);
1140 IPMI_ADD_RSP_DATA(0);
1142 out:
1143 return;
1146 static void get_sdr_rep_info(IPMIBmcSim *ibs,
1147 uint8_t *cmd, unsigned int cmd_len,
1148 uint8_t *rsp, unsigned int *rsp_len,
1149 unsigned int max_rsp_len)
1151 unsigned int i;
1153 IPMI_ADD_RSP_DATA(0x51); /* Conform to IPMI 1.5 spec */
1154 IPMI_ADD_RSP_DATA(ibs->sdr.next_rec_id & 0xff);
1155 IPMI_ADD_RSP_DATA((ibs->sdr.next_rec_id >> 8) & 0xff);
1156 IPMI_ADD_RSP_DATA((MAX_SDR_SIZE - ibs->sdr.next_free) & 0xff);
1157 IPMI_ADD_RSP_DATA(((MAX_SDR_SIZE - ibs->sdr.next_free) >> 8) & 0xff);
1158 for (i = 0; i < 4; i++) {
1159 IPMI_ADD_RSP_DATA(ibs->sdr.last_addition[i]);
1161 for (i = 0; i < 4; i++) {
1162 IPMI_ADD_RSP_DATA(ibs->sdr.last_clear[i]);
1164 /* Only modal support, reserve supported */
1165 IPMI_ADD_RSP_DATA((ibs->sdr.overflow << 7) | 0x22);
1166 out:
1167 return;
1170 static void reserve_sdr_rep(IPMIBmcSim *ibs,
1171 uint8_t *cmd, unsigned int cmd_len,
1172 uint8_t *rsp, unsigned int *rsp_len,
1173 unsigned int max_rsp_len)
1175 IPMI_ADD_RSP_DATA(ibs->sdr.reservation & 0xff);
1176 IPMI_ADD_RSP_DATA((ibs->sdr.reservation >> 8) & 0xff);
1177 out:
1178 return;
1181 static void get_sdr(IPMIBmcSim *ibs,
1182 uint8_t *cmd, unsigned int cmd_len,
1183 uint8_t *rsp, unsigned int *rsp_len,
1184 unsigned int max_rsp_len)
1186 unsigned int pos;
1187 uint16_t nextrec;
1189 IPMI_CHECK_CMD_LEN(8);
1190 if (cmd[6]) {
1191 IPMI_CHECK_RESERVATION(2, ibs->sdr.reservation);
1193 pos = 0;
1194 if (sdr_find_entry(&ibs->sdr, cmd[4] | (cmd[5] << 8),
1195 &pos, &nextrec)) {
1196 rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1197 goto out;
1199 if (cmd[6] > (ibs->sdr.sdr[pos + 4])) {
1200 rsp[2] = IPMI_CC_PARM_OUT_OF_RANGE;
1201 goto out;
1204 IPMI_ADD_RSP_DATA(nextrec & 0xff);
1205 IPMI_ADD_RSP_DATA((nextrec >> 8) & 0xff);
1207 if (cmd[7] == 0xff) {
1208 cmd[7] = ibs->sdr.sdr[pos + 4] - cmd[6];
1211 if ((cmd[7] + *rsp_len) > max_rsp_len) {
1212 rsp[2] = IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES;
1213 goto out;
1215 memcpy(rsp + *rsp_len, ibs->sdr.sdr + pos + cmd[6], cmd[7]);
1216 *rsp_len += cmd[7];
1217 out:
1218 return;
1221 static void add_sdr(IPMIBmcSim *ibs,
1222 uint8_t *cmd, unsigned int cmd_len,
1223 uint8_t *rsp, unsigned int *rsp_len,
1224 unsigned int max_rsp_len)
1226 uint16_t recid;
1228 if (sdr_add_entry(ibs, cmd + 2, cmd_len - 2, &recid)) {
1229 rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1230 goto out;
1232 IPMI_ADD_RSP_DATA(recid & 0xff);
1233 IPMI_ADD_RSP_DATA((recid >> 8) & 0xff);
1234 out:
1235 return;
1238 static void clear_sdr_rep(IPMIBmcSim *ibs,
1239 uint8_t *cmd, unsigned int cmd_len,
1240 uint8_t *rsp, unsigned int *rsp_len,
1241 unsigned int max_rsp_len)
1243 IPMI_CHECK_CMD_LEN(8);
1244 IPMI_CHECK_RESERVATION(2, ibs->sdr.reservation);
1245 if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
1246 rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1247 goto out;
1249 if (cmd[7] == 0xaa) {
1250 ibs->sdr.next_free = 0;
1251 ibs->sdr.overflow = 0;
1252 set_timestamp(ibs, ibs->sdr.last_clear);
1253 IPMI_ADD_RSP_DATA(1); /* Erasure complete */
1254 sdr_inc_reservation(&ibs->sdr);
1255 } else if (cmd[7] == 0) {
1256 IPMI_ADD_RSP_DATA(1); /* Erasure complete */
1257 } else {
1258 rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1259 goto out;
1261 out:
1262 return;
1265 static void get_sel_info(IPMIBmcSim *ibs,
1266 uint8_t *cmd, unsigned int cmd_len,
1267 uint8_t *rsp, unsigned int *rsp_len,
1268 unsigned int max_rsp_len)
1270 unsigned int i, val;
1272 IPMI_ADD_RSP_DATA(0x51); /* Conform to IPMI 1.5 */
1273 IPMI_ADD_RSP_DATA(ibs->sel.next_free & 0xff);
1274 IPMI_ADD_RSP_DATA((ibs->sel.next_free >> 8) & 0xff);
1275 val = (MAX_SEL_SIZE - ibs->sel.next_free) * 16;
1276 IPMI_ADD_RSP_DATA(val & 0xff);
1277 IPMI_ADD_RSP_DATA((val >> 8) & 0xff);
1278 for (i = 0; i < 4; i++) {
1279 IPMI_ADD_RSP_DATA(ibs->sel.last_addition[i]);
1281 for (i = 0; i < 4; i++) {
1282 IPMI_ADD_RSP_DATA(ibs->sel.last_clear[i]);
1284 /* Only support Reserve SEL */
1285 IPMI_ADD_RSP_DATA((ibs->sel.overflow << 7) | 0x02);
1286 out:
1287 return;
1290 static void reserve_sel(IPMIBmcSim *ibs,
1291 uint8_t *cmd, unsigned int cmd_len,
1292 uint8_t *rsp, unsigned int *rsp_len,
1293 unsigned int max_rsp_len)
1295 IPMI_ADD_RSP_DATA(ibs->sel.reservation & 0xff);
1296 IPMI_ADD_RSP_DATA((ibs->sel.reservation >> 8) & 0xff);
1297 out:
1298 return;
1301 static void get_sel_entry(IPMIBmcSim *ibs,
1302 uint8_t *cmd, unsigned int cmd_len,
1303 uint8_t *rsp, unsigned int *rsp_len,
1304 unsigned int max_rsp_len)
1306 unsigned int val;
1308 IPMI_CHECK_CMD_LEN(8);
1309 if (cmd[6]) {
1310 IPMI_CHECK_RESERVATION(2, ibs->sel.reservation);
1312 if (ibs->sel.next_free == 0) {
1313 rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1314 goto out;
1316 if (cmd[6] > 15) {
1317 rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1318 goto out;
1320 if (cmd[7] == 0xff) {
1321 cmd[7] = 16;
1322 } else if ((cmd[7] + cmd[6]) > 16) {
1323 rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1324 goto out;
1325 } else {
1326 cmd[7] += cmd[6];
1329 val = cmd[4] | (cmd[5] << 8);
1330 if (val == 0xffff) {
1331 val = ibs->sel.next_free - 1;
1332 } else if (val >= ibs->sel.next_free) {
1333 rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1334 goto out;
1336 if ((val + 1) == ibs->sel.next_free) {
1337 IPMI_ADD_RSP_DATA(0xff);
1338 IPMI_ADD_RSP_DATA(0xff);
1339 } else {
1340 IPMI_ADD_RSP_DATA((val + 1) & 0xff);
1341 IPMI_ADD_RSP_DATA(((val + 1) >> 8) & 0xff);
1343 for (; cmd[6] < cmd[7]; cmd[6]++) {
1344 IPMI_ADD_RSP_DATA(ibs->sel.sel[val][cmd[6]]);
1346 out:
1347 return;
1350 static void add_sel_entry(IPMIBmcSim *ibs,
1351 uint8_t *cmd, unsigned int cmd_len,
1352 uint8_t *rsp, unsigned int *rsp_len,
1353 unsigned int max_rsp_len)
1355 IPMI_CHECK_CMD_LEN(18);
1356 if (sel_add_event(ibs, cmd + 2)) {
1357 rsp[2] = IPMI_CC_OUT_OF_SPACE;
1358 goto out;
1360 /* sel_add_event fills in the record number. */
1361 IPMI_ADD_RSP_DATA(cmd[2]);
1362 IPMI_ADD_RSP_DATA(cmd[3]);
1363 out:
1364 return;
1367 static void clear_sel(IPMIBmcSim *ibs,
1368 uint8_t *cmd, unsigned int cmd_len,
1369 uint8_t *rsp, unsigned int *rsp_len,
1370 unsigned int max_rsp_len)
1372 IPMI_CHECK_CMD_LEN(8);
1373 IPMI_CHECK_RESERVATION(2, ibs->sel.reservation);
1374 if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
1375 rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1376 goto out;
1378 if (cmd[7] == 0xaa) {
1379 ibs->sel.next_free = 0;
1380 ibs->sel.overflow = 0;
1381 set_timestamp(ibs, ibs->sdr.last_clear);
1382 IPMI_ADD_RSP_DATA(1); /* Erasure complete */
1383 sel_inc_reservation(&ibs->sel);
1384 } else if (cmd[7] == 0) {
1385 IPMI_ADD_RSP_DATA(1); /* Erasure complete */
1386 } else {
1387 rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1388 goto out;
1390 out:
1391 return;
1394 static void get_sel_time(IPMIBmcSim *ibs,
1395 uint8_t *cmd, unsigned int cmd_len,
1396 uint8_t *rsp, unsigned int *rsp_len,
1397 unsigned int max_rsp_len)
1399 uint32_t val;
1400 struct ipmi_time now;
1402 ipmi_gettime(&now);
1403 val = now.tv_sec + ibs->sel.time_offset;
1404 IPMI_ADD_RSP_DATA(val & 0xff);
1405 IPMI_ADD_RSP_DATA((val >> 8) & 0xff);
1406 IPMI_ADD_RSP_DATA((val >> 16) & 0xff);
1407 IPMI_ADD_RSP_DATA((val >> 24) & 0xff);
1408 out:
1409 return;
1412 static void set_sel_time(IPMIBmcSim *ibs,
1413 uint8_t *cmd, unsigned int cmd_len,
1414 uint8_t *rsp, unsigned int *rsp_len,
1415 unsigned int max_rsp_len)
1417 uint32_t val;
1418 struct ipmi_time now;
1420 IPMI_CHECK_CMD_LEN(6);
1421 val = cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24);
1422 ipmi_gettime(&now);
1423 ibs->sel.time_offset = now.tv_sec - ((long) val);
1424 out:
1425 return;
1428 static void set_sensor_evt_enable(IPMIBmcSim *ibs,
1429 uint8_t *cmd, unsigned int cmd_len,
1430 uint8_t *rsp, unsigned int *rsp_len,
1431 unsigned int max_rsp_len)
1433 IPMISensor *sens;
1435 IPMI_CHECK_CMD_LEN(4);
1436 if ((cmd[2] > MAX_SENSORS) ||
1437 !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1438 rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1439 goto out;
1441 sens = ibs->sensors + cmd[2];
1442 switch ((cmd[3] >> 4) & 0x3) {
1443 case 0: /* Do not change */
1444 break;
1445 case 1: /* Enable bits */
1446 if (cmd_len > 4) {
1447 sens->assert_enable |= cmd[4];
1449 if (cmd_len > 5) {
1450 sens->assert_enable |= cmd[5] << 8;
1452 if (cmd_len > 6) {
1453 sens->deassert_enable |= cmd[6];
1455 if (cmd_len > 7) {
1456 sens->deassert_enable |= cmd[7] << 8;
1458 break;
1459 case 2: /* Disable bits */
1460 if (cmd_len > 4) {
1461 sens->assert_enable &= ~cmd[4];
1463 if (cmd_len > 5) {
1464 sens->assert_enable &= ~(cmd[5] << 8);
1466 if (cmd_len > 6) {
1467 sens->deassert_enable &= ~cmd[6];
1469 if (cmd_len > 7) {
1470 sens->deassert_enable &= ~(cmd[7] << 8);
1472 break;
1473 case 3:
1474 rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1475 goto out;
1477 IPMI_SENSOR_SET_RET_STATUS(sens, cmd[3]);
1478 out:
1479 return;
1482 static void get_sensor_evt_enable(IPMIBmcSim *ibs,
1483 uint8_t *cmd, unsigned int cmd_len,
1484 uint8_t *rsp, unsigned int *rsp_len,
1485 unsigned int max_rsp_len)
1487 IPMISensor *sens;
1489 IPMI_CHECK_CMD_LEN(3);
1490 if ((cmd[2] > MAX_SENSORS) ||
1491 !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1492 rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1493 goto out;
1495 sens = ibs->sensors + cmd[2];
1496 IPMI_ADD_RSP_DATA(IPMI_SENSOR_GET_RET_STATUS(sens));
1497 IPMI_ADD_RSP_DATA(sens->assert_enable & 0xff);
1498 IPMI_ADD_RSP_DATA((sens->assert_enable >> 8) & 0xff);
1499 IPMI_ADD_RSP_DATA(sens->deassert_enable & 0xff);
1500 IPMI_ADD_RSP_DATA((sens->deassert_enable >> 8) & 0xff);
1501 out:
1502 return;
1505 static void rearm_sensor_evts(IPMIBmcSim *ibs,
1506 uint8_t *cmd, unsigned int cmd_len,
1507 uint8_t *rsp, unsigned int *rsp_len,
1508 unsigned int max_rsp_len)
1510 IPMISensor *sens;
1512 IPMI_CHECK_CMD_LEN(4);
1513 if ((cmd[2] > MAX_SENSORS) ||
1514 !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1515 rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1516 goto out;
1518 sens = ibs->sensors + cmd[2];
1520 if ((cmd[3] & 0x80) == 0) {
1521 /* Just clear everything */
1522 sens->states = 0;
1523 goto out;
1525 out:
1526 return;
1529 static void get_sensor_evt_status(IPMIBmcSim *ibs,
1530 uint8_t *cmd, unsigned int cmd_len,
1531 uint8_t *rsp, unsigned int *rsp_len,
1532 unsigned int max_rsp_len)
1534 IPMISensor *sens;
1536 IPMI_CHECK_CMD_LEN(3);
1537 if ((cmd[2] > MAX_SENSORS) ||
1538 !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1539 rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1540 goto out;
1542 sens = ibs->sensors + cmd[2];
1543 IPMI_ADD_RSP_DATA(sens->reading);
1544 IPMI_ADD_RSP_DATA(IPMI_SENSOR_GET_RET_STATUS(sens));
1545 IPMI_ADD_RSP_DATA(sens->assert_states & 0xff);
1546 IPMI_ADD_RSP_DATA((sens->assert_states >> 8) & 0xff);
1547 IPMI_ADD_RSP_DATA(sens->deassert_states & 0xff);
1548 IPMI_ADD_RSP_DATA((sens->deassert_states >> 8) & 0xff);
1549 out:
1550 return;
1553 static void get_sensor_reading(IPMIBmcSim *ibs,
1554 uint8_t *cmd, unsigned int cmd_len,
1555 uint8_t *rsp, unsigned int *rsp_len,
1556 unsigned int max_rsp_len)
1558 IPMISensor *sens;
1560 IPMI_CHECK_CMD_LEN(3);
1561 if ((cmd[2] > MAX_SENSORS) ||
1562 !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1563 rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1564 goto out;
1566 sens = ibs->sensors + cmd[2];
1567 IPMI_ADD_RSP_DATA(sens->reading);
1568 IPMI_ADD_RSP_DATA(IPMI_SENSOR_GET_RET_STATUS(sens));
1569 IPMI_ADD_RSP_DATA(sens->states & 0xff);
1570 if (IPMI_SENSOR_IS_DISCRETE(sens)) {
1571 IPMI_ADD_RSP_DATA((sens->states >> 8) & 0xff);
1573 out:
1574 return;
1577 static const IPMICmdHandler chassis_cmds[IPMI_NETFN_CHASSIS_MAXCMD] = {
1578 [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = chassis_capabilities,
1579 [IPMI_CMD_GET_CHASSIS_STATUS] = chassis_status,
1580 [IPMI_CMD_CHASSIS_CONTROL] = chassis_control
1582 static const IPMINetfn chassis_netfn = {
1583 .cmd_nums = IPMI_NETFN_CHASSIS_MAXCMD,
1584 .cmd_handlers = chassis_cmds
1587 static const IPMICmdHandler
1588 sensor_event_cmds[IPMI_NETFN_SENSOR_EVENT_MAXCMD] = {
1589 [IPMI_CMD_SET_SENSOR_EVT_ENABLE] = set_sensor_evt_enable,
1590 [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = get_sensor_evt_enable,
1591 [IPMI_CMD_REARM_SENSOR_EVTS] = rearm_sensor_evts,
1592 [IPMI_CMD_GET_SENSOR_EVT_STATUS] = get_sensor_evt_status,
1593 [IPMI_CMD_GET_SENSOR_READING] = get_sensor_reading
1595 static const IPMINetfn sensor_event_netfn = {
1596 .cmd_nums = IPMI_NETFN_SENSOR_EVENT_MAXCMD,
1597 .cmd_handlers = sensor_event_cmds
1600 static const IPMICmdHandler app_cmds[IPMI_NETFN_APP_MAXCMD] = {
1601 [IPMI_CMD_GET_DEVICE_ID] = get_device_id,
1602 [IPMI_CMD_COLD_RESET] = cold_reset,
1603 [IPMI_CMD_WARM_RESET] = warm_reset,
1604 [IPMI_CMD_SET_BMC_GLOBAL_ENABLES] = set_bmc_global_enables,
1605 [IPMI_CMD_GET_BMC_GLOBAL_ENABLES] = get_bmc_global_enables,
1606 [IPMI_CMD_CLR_MSG_FLAGS] = clr_msg_flags,
1607 [IPMI_CMD_GET_MSG_FLAGS] = get_msg_flags,
1608 [IPMI_CMD_GET_MSG] = get_msg,
1609 [IPMI_CMD_SEND_MSG] = send_msg,
1610 [IPMI_CMD_READ_EVT_MSG_BUF] = read_evt_msg_buf,
1611 [IPMI_CMD_RESET_WATCHDOG_TIMER] = reset_watchdog_timer,
1612 [IPMI_CMD_SET_WATCHDOG_TIMER] = set_watchdog_timer,
1613 [IPMI_CMD_GET_WATCHDOG_TIMER] = get_watchdog_timer,
1615 static const IPMINetfn app_netfn = {
1616 .cmd_nums = IPMI_NETFN_APP_MAXCMD,
1617 .cmd_handlers = app_cmds
1620 static const IPMICmdHandler storage_cmds[IPMI_NETFN_STORAGE_MAXCMD] = {
1621 [IPMI_CMD_GET_SDR_REP_INFO] = get_sdr_rep_info,
1622 [IPMI_CMD_RESERVE_SDR_REP] = reserve_sdr_rep,
1623 [IPMI_CMD_GET_SDR] = get_sdr,
1624 [IPMI_CMD_ADD_SDR] = add_sdr,
1625 [IPMI_CMD_CLEAR_SDR_REP] = clear_sdr_rep,
1626 [IPMI_CMD_GET_SEL_INFO] = get_sel_info,
1627 [IPMI_CMD_RESERVE_SEL] = reserve_sel,
1628 [IPMI_CMD_GET_SEL_ENTRY] = get_sel_entry,
1629 [IPMI_CMD_ADD_SEL_ENTRY] = add_sel_entry,
1630 [IPMI_CMD_CLEAR_SEL] = clear_sel,
1631 [IPMI_CMD_GET_SEL_TIME] = get_sel_time,
1632 [IPMI_CMD_SET_SEL_TIME] = set_sel_time,
1635 static const IPMINetfn storage_netfn = {
1636 .cmd_nums = IPMI_NETFN_STORAGE_MAXCMD,
1637 .cmd_handlers = storage_cmds
1640 static void register_cmds(IPMIBmcSim *s)
1642 ipmi_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn);
1643 ipmi_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn);
1644 ipmi_register_netfn(s, IPMI_NETFN_APP, &app_netfn);
1645 ipmi_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn);
1648 static const uint8_t init_sdrs[] = {
1649 /* Watchdog device */
1650 0x00, 0x00, 0x51, 0x02, 35, 0x20, 0x00, 0x00,
1651 0x23, 0x01, 0x63, 0x00, 0x23, 0x6f, 0x0f, 0x01,
1652 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1653 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8,
1654 'W', 'a', 't', 'c', 'h', 'd', 'o', 'g',
1655 /* End */
1656 0xff, 0xff, 0x00, 0x00, 0x00
1659 static const VMStateDescription vmstate_ipmi_sim = {
1660 .name = TYPE_IPMI_BMC_SIMULATOR,
1661 .version_id = 1,
1662 .minimum_version_id = 1,
1663 .fields = (VMStateField[]) {
1664 VMSTATE_UINT8(bmc_global_enables, IPMIBmcSim),
1665 VMSTATE_UINT8(msg_flags, IPMIBmcSim),
1666 VMSTATE_BOOL(watchdog_initialized, IPMIBmcSim),
1667 VMSTATE_UINT8(watchdog_use, IPMIBmcSim),
1668 VMSTATE_UINT8(watchdog_action, IPMIBmcSim),
1669 VMSTATE_UINT8(watchdog_pretimeout, IPMIBmcSim),
1670 VMSTATE_BOOL(watchdog_expired, IPMIBmcSim),
1671 VMSTATE_UINT16(watchdog_timeout, IPMIBmcSim),
1672 VMSTATE_BOOL(watchdog_running, IPMIBmcSim),
1673 VMSTATE_BOOL(watchdog_preaction_ran, IPMIBmcSim),
1674 VMSTATE_INT64(watchdog_expiry, IPMIBmcSim),
1675 VMSTATE_UINT8_ARRAY(evtbuf, IPMIBmcSim, 16),
1676 VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].status, IPMIBmcSim),
1677 VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].reading, IPMIBmcSim),
1678 VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].states, IPMIBmcSim),
1679 VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_states, IPMIBmcSim),
1680 VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].deassert_states,
1681 IPMIBmcSim),
1682 VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_enable, IPMIBmcSim),
1683 VMSTATE_END_OF_LIST()
1687 static void ipmi_sim_init(Object *obj)
1689 IPMIBmc *b = IPMI_BMC(obj);
1690 unsigned int i;
1691 unsigned int recid;
1692 IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
1694 qemu_mutex_init(&ibs->lock);
1695 QTAILQ_INIT(&ibs->rcvbufs);
1697 ibs->bmc_global_enables = (1 << IPMI_BMC_EVENT_LOG_BIT);
1698 ibs->device_id = 0x20;
1699 ibs->ipmi_version = 0x02; /* IPMI 2.0 */
1700 for (i = 0; i < 4; i++) {
1701 ibs->sel.last_addition[i] = 0xff;
1702 ibs->sel.last_clear[i] = 0xff;
1703 ibs->sdr.last_addition[i] = 0xff;
1704 ibs->sdr.last_clear[i] = 0xff;
1707 for (i = 0;;) {
1708 int len;
1709 if ((i + 5) > sizeof(init_sdrs)) {
1710 error_report("Problem with recid 0x%4.4x: \n", i);
1711 return;
1713 len = init_sdrs[i + 4];
1714 recid = init_sdrs[i] | (init_sdrs[i + 1] << 8);
1715 if (recid == 0xffff) {
1716 break;
1718 if ((i + len + 5) > sizeof(init_sdrs)) {
1719 error_report("Problem with recid 0x%4.4x\n", i);
1720 return;
1722 sdr_add_entry(ibs, init_sdrs + i, len, NULL);
1723 i += len + 5;
1726 ipmi_init_sensors_from_sdrs(ibs);
1727 register_cmds(ibs);
1729 ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs);
1731 vmstate_register(NULL, 0, &vmstate_ipmi_sim, ibs);
1734 static void ipmi_sim_class_init(ObjectClass *oc, void *data)
1736 IPMIBmcClass *bk = IPMI_BMC_CLASS(oc);
1738 bk->handle_command = ipmi_sim_handle_command;
1741 static const TypeInfo ipmi_sim_type = {
1742 .name = TYPE_IPMI_BMC_SIMULATOR,
1743 .parent = TYPE_IPMI_BMC,
1744 .instance_size = sizeof(IPMIBmcSim),
1745 .instance_init = ipmi_sim_init,
1746 .class_init = ipmi_sim_class_init,
1749 static void ipmi_sim_register_types(void)
1751 type_register_static(&ipmi_sim_type);
1754 type_init(ipmi_sim_register_types)