]> git.proxmox.com Git - mirror_qemu.git/blame - hw/ipmi/ipmi_bmc_sim.c
ppc: add IPMI support
[mirror_qemu.git] / hw / ipmi / ipmi_bmc_sim.c
CommitLineData
8bfffbcc
CM
1/*
2 * IPMI BMC emulation
3 *
4 * Copyright (c) 2015 Corey Minyard, MontaVista Software, LLC
5 *
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:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
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.
23 */
24
0430891c 25#include "qemu/osdep.h"
52ba4d50 26#include "sysemu/sysemu.h"
8bfffbcc
CM
27#include "qemu/timer.h"
28#include "hw/ipmi/ipmi.h"
29#include "qemu/error-report.h"
30
31#define IPMI_NETFN_CHASSIS 0x00
8bfffbcc
CM
32
33#define IPMI_CMD_GET_CHASSIS_CAPABILITIES 0x00
34#define IPMI_CMD_GET_CHASSIS_STATUS 0x01
35#define IPMI_CMD_CHASSIS_CONTROL 0x02
b7088392 36#define IPMI_CMD_GET_SYS_RESTART_CAUSE 0x09
8bfffbcc
CM
37
38#define IPMI_NETFN_SENSOR_EVENT 0x04
8bfffbcc
CM
39
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
728710e1
CLG
45#define IPMI_CMD_SET_SENSOR_TYPE 0x2e
46#define IPMI_CMD_GET_SENSOR_TYPE 0x2f
8bfffbcc
CM
47
48/* #define IPMI_NETFN_APP 0x06 In ipmi.h */
8bfffbcc
CM
49
50#define IPMI_CMD_GET_DEVICE_ID 0x01
51#define IPMI_CMD_COLD_RESET 0x02
52#define IPMI_CMD_WARM_RESET 0x03
52ba4d50
CLG
53#define IPMI_CMD_SET_ACPI_POWER_STATE 0x06
54#define IPMI_CMD_GET_ACPI_POWER_STATE 0x07
55#define IPMI_CMD_GET_DEVICE_GUID 0x08
8bfffbcc
CM
56#define IPMI_CMD_RESET_WATCHDOG_TIMER 0x22
57#define IPMI_CMD_SET_WATCHDOG_TIMER 0x24
58#define IPMI_CMD_GET_WATCHDOG_TIMER 0x25
59#define IPMI_CMD_SET_BMC_GLOBAL_ENABLES 0x2e
60#define IPMI_CMD_GET_BMC_GLOBAL_ENABLES 0x2f
61#define IPMI_CMD_CLR_MSG_FLAGS 0x30
62#define IPMI_CMD_GET_MSG_FLAGS 0x31
63#define IPMI_CMD_GET_MSG 0x33
64#define IPMI_CMD_SEND_MSG 0x34
65#define IPMI_CMD_READ_EVT_MSG_BUF 0x35
66
67#define IPMI_NETFN_STORAGE 0x0a
8bfffbcc
CM
68
69#define IPMI_CMD_GET_SDR_REP_INFO 0x20
70#define IPMI_CMD_GET_SDR_REP_ALLOC_INFO 0x21
71#define IPMI_CMD_RESERVE_SDR_REP 0x22
72#define IPMI_CMD_GET_SDR 0x23
73#define IPMI_CMD_ADD_SDR 0x24
74#define IPMI_CMD_PARTIAL_ADD_SDR 0x25
75#define IPMI_CMD_DELETE_SDR 0x26
76#define IPMI_CMD_CLEAR_SDR_REP 0x27
77#define IPMI_CMD_GET_SDR_REP_TIME 0x28
78#define IPMI_CMD_SET_SDR_REP_TIME 0x29
79#define IPMI_CMD_ENTER_SDR_REP_UPD_MODE 0x2A
80#define IPMI_CMD_EXIT_SDR_REP_UPD_MODE 0x2B
81#define IPMI_CMD_RUN_INIT_AGENT 0x2C
82#define IPMI_CMD_GET_SEL_INFO 0x40
83#define IPMI_CMD_GET_SEL_ALLOC_INFO 0x41
84#define IPMI_CMD_RESERVE_SEL 0x42
85#define IPMI_CMD_GET_SEL_ENTRY 0x43
86#define IPMI_CMD_ADD_SEL_ENTRY 0x44
87#define IPMI_CMD_PARTIAL_ADD_SEL_ENTRY 0x45
88#define IPMI_CMD_DELETE_SEL_ENTRY 0x46
89#define IPMI_CMD_CLEAR_SEL 0x47
90#define IPMI_CMD_GET_SEL_TIME 0x48
91#define IPMI_CMD_SET_SEL_TIME 0x49
92
93
94/* Same as a timespec struct. */
95struct ipmi_time {
96 long tv_sec;
97 long tv_nsec;
98};
99
100#define MAX_SEL_SIZE 128
101
102typedef struct IPMISel {
103 uint8_t sel[MAX_SEL_SIZE][16];
104 unsigned int next_free;
105 long time_offset;
106 uint16_t reservation;
107 uint8_t last_addition[4];
108 uint8_t last_clear[4];
109 uint8_t overflow;
110} IPMISel;
111
112#define MAX_SDR_SIZE 16384
113
114typedef struct IPMISdr {
115 uint8_t sdr[MAX_SDR_SIZE];
116 unsigned int next_free;
117 uint16_t next_rec_id;
118 uint16_t reservation;
119 uint8_t last_addition[4];
120 uint8_t last_clear[4];
121 uint8_t overflow;
122} IPMISdr;
123
124typedef struct IPMISensor {
125 uint8_t status;
126 uint8_t reading;
127 uint16_t states_suppt;
128 uint16_t assert_suppt;
129 uint16_t deassert_suppt;
130 uint16_t states;
131 uint16_t assert_states;
132 uint16_t deassert_states;
133 uint16_t assert_enable;
134 uint16_t deassert_enable;
135 uint8_t sensor_type;
136 uint8_t evt_reading_type_code;
137} IPMISensor;
138#define IPMI_SENSOR_GET_PRESENT(s) ((s)->status & 0x01)
139#define IPMI_SENSOR_SET_PRESENT(s, v) ((s)->status = (s->status & ~0x01) | \
140 !!(v))
141#define IPMI_SENSOR_GET_SCAN_ON(s) ((s)->status & 0x40)
142#define IPMI_SENSOR_SET_SCAN_ON(s, v) ((s)->status = (s->status & ~0x40) | \
143 ((!!(v)) << 6))
144#define IPMI_SENSOR_GET_EVENTS_ON(s) ((s)->status & 0x80)
145#define IPMI_SENSOR_SET_EVENTS_ON(s, v) ((s)->status = (s->status & ~0x80) | \
146 ((!!(v)) << 7))
147#define IPMI_SENSOR_GET_RET_STATUS(s) ((s)->status & 0xc0)
148#define IPMI_SENSOR_SET_RET_STATUS(s, v) ((s)->status = (s->status & ~0xc0) | \
149 (v & 0xc0))
150#define IPMI_SENSOR_IS_DISCRETE(s) ((s)->evt_reading_type_code != 1)
151
152#define MAX_SENSORS 20
153#define IPMI_WATCHDOG_SENSOR 0
154
155typedef struct IPMIBmcSim IPMIBmcSim;
a580d820 156typedef struct RspBuffer RspBuffer;
8bfffbcc
CM
157
158#define MAX_NETFNS 64
4f298a4b
CLG
159
160typedef struct IPMICmdHandler {
161 void (*cmd_handler)(IPMIBmcSim *s,
162 uint8_t *cmd, unsigned int cmd_len,
a580d820 163 RspBuffer *rsp);
4f298a4b
CLG
164 unsigned int cmd_len_min;
165} IPMICmdHandler;
166
8bfffbcc
CM
167typedef struct IPMINetfn {
168 unsigned int cmd_nums;
169 const IPMICmdHandler *cmd_handlers;
170} IPMINetfn;
171
172typedef struct IPMIRcvBufEntry {
173 QTAILQ_ENTRY(IPMIRcvBufEntry) entry;
174 uint8_t len;
175 uint8_t buf[MAX_IPMI_MSG_SIZE];
176} IPMIRcvBufEntry;
177
178#define TYPE_IPMI_BMC_SIMULATOR "ipmi-bmc-sim"
179#define IPMI_BMC_SIMULATOR(obj) OBJECT_CHECK(IPMIBmcSim, (obj), \
180 TYPE_IPMI_BMC_SIMULATOR)
181struct IPMIBmcSim {
182 IPMIBmc parent;
183
184 QEMUTimer *timer;
185
186 uint8_t bmc_global_enables;
187 uint8_t msg_flags;
188
189 bool watchdog_initialized;
190 uint8_t watchdog_use;
191 uint8_t watchdog_action;
192 uint8_t watchdog_pretimeout; /* In seconds */
193 bool watchdog_expired;
194 uint16_t watchdog_timeout; /* in 100's of milliseconds */
195
196 bool watchdog_running;
197 bool watchdog_preaction_ran;
198 int64_t watchdog_expiry;
199
200 uint8_t device_id;
201 uint8_t ipmi_version;
202 uint8_t device_rev;
203 uint8_t fwrev1;
204 uint8_t fwrev2;
205 uint8_t mfg_id[3];
206 uint8_t product_id[2];
207
b7088392
CLG
208 uint8_t restart_cause;
209
52ba4d50
CLG
210 uint8_t acpi_power_state[2];
211 uint8_t uuid[16];
212
8bfffbcc
CM
213 IPMISel sel;
214 IPMISdr sdr;
215 IPMISensor sensors[MAX_SENSORS];
216
217 /* Odd netfns are for responses, so we only need the even ones. */
218 const IPMINetfn *netfns[MAX_NETFNS / 2];
219
8bfffbcc
CM
220 /* We allow one event in the buffer */
221 uint8_t evtbuf[16];
222
223 QTAILQ_HEAD(, IPMIRcvBufEntry) rcvbufs;
224};
225
226#define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK (1 << 3)
227#define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL (1 << 1)
228#define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE (1 << 0)
229#define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(s) \
230 (IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK & (s)->msg_flags)
231#define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(s) \
232 (IPMI_BMC_MSG_FLAG_EVT_BUF_FULL & (s)->msg_flags)
233#define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(s) \
234 (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE & (s)->msg_flags)
235
236#define IPMI_BMC_RCV_MSG_QUEUE_INT_BIT 0
237#define IPMI_BMC_EVBUF_FULL_INT_BIT 1
238#define IPMI_BMC_EVENT_MSG_BUF_BIT 2
239#define IPMI_BMC_EVENT_LOG_BIT 3
240#define IPMI_BMC_MSG_INTS_ON(s) ((s)->bmc_global_enables & \
241 (1 << IPMI_BMC_RCV_MSG_QUEUE_INT_BIT))
242#define IPMI_BMC_EVBUF_FULL_INT_ENABLED(s) ((s)->bmc_global_enables & \
243 (1 << IPMI_BMC_EVBUF_FULL_INT_BIT))
244#define IPMI_BMC_EVENT_LOG_ENABLED(s) ((s)->bmc_global_enables & \
245 (1 << IPMI_BMC_EVENT_LOG_BIT))
246#define IPMI_BMC_EVENT_MSG_BUF_ENABLED(s) ((s)->bmc_global_enables & \
247 (1 << IPMI_BMC_EVENT_MSG_BUF_BIT))
248
249#define IPMI_BMC_WATCHDOG_USE_MASK 0xc7
250#define IPMI_BMC_WATCHDOG_ACTION_MASK 0x77
251#define IPMI_BMC_WATCHDOG_GET_USE(s) ((s)->watchdog_use & 0x7)
252#define IPMI_BMC_WATCHDOG_GET_DONT_LOG(s) (((s)->watchdog_use >> 7) & 0x1)
253#define IPMI_BMC_WATCHDOG_GET_DONT_STOP(s) (((s)->watchdog_use >> 6) & 0x1)
254#define IPMI_BMC_WATCHDOG_GET_PRE_ACTION(s) (((s)->watchdog_action >> 4) & 0x7)
255#define IPMI_BMC_WATCHDOG_PRE_NONE 0
256#define IPMI_BMC_WATCHDOG_PRE_SMI 1
257#define IPMI_BMC_WATCHDOG_PRE_NMI 2
258#define IPMI_BMC_WATCHDOG_PRE_MSG_INT 3
259#define IPMI_BMC_WATCHDOG_GET_ACTION(s) ((s)->watchdog_action & 0x7)
260#define IPMI_BMC_WATCHDOG_ACTION_NONE 0
261#define IPMI_BMC_WATCHDOG_ACTION_RESET 1
262#define IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN 2
263#define IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE 3
264
a580d820
CLG
265struct RspBuffer {
266 uint8_t buffer[MAX_IPMI_MSG_SIZE];
267 unsigned int len;
268};
269
270#define RSP_BUFFER_INITIALIZER { }
8bfffbcc 271
6acb971a
CLG
272static inline void rsp_buffer_set_error(RspBuffer *rsp, uint8_t byte)
273{
274 rsp->buffer[2] = byte;
275}
276
8bfffbcc 277/* Add a byte to the response. */
a580d820
CLG
278static inline void rsp_buffer_push(RspBuffer *rsp, uint8_t byte)
279{
280 if (rsp->len >= sizeof(rsp->buffer)) {
6acb971a 281 rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
a580d820
CLG
282 return;
283 }
284 rsp->buffer[rsp->len++] = byte;
285}
286
287static inline void rsp_buffer_pushmore(RspBuffer *rsp, uint8_t *bytes,
288 unsigned int n)
289{
290 if (rsp->len + n >= sizeof(rsp->buffer)) {
6acb971a 291 rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
a580d820
CLG
292 return;
293 }
294
295 memcpy(&rsp->buffer[rsp->len], bytes, n);
296 rsp->len += n;
297}
8bfffbcc 298
8bfffbcc
CM
299static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs);
300
301static void ipmi_gettime(struct ipmi_time *time)
302{
303 int64_t stime;
304
305 stime = qemu_clock_get_ns(QEMU_CLOCK_HOST);
306 time->tv_sec = stime / 1000000000LL;
307 time->tv_nsec = stime % 1000000000LL;
308}
309
310static int64_t ipmi_getmonotime(void)
311{
312 return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
313}
314
315static void ipmi_timeout(void *opaque)
316{
317 IPMIBmcSim *ibs = opaque;
318
319 ipmi_sim_handle_timeout(ibs);
320}
321
322static void set_timestamp(IPMIBmcSim *ibs, uint8_t *ts)
323{
324 unsigned int val;
325 struct ipmi_time now;
326
327 ipmi_gettime(&now);
328 val = now.tv_sec + ibs->sel.time_offset;
329 ts[0] = val & 0xff;
330 ts[1] = (val >> 8) & 0xff;
331 ts[2] = (val >> 16) & 0xff;
332 ts[3] = (val >> 24) & 0xff;
333}
334
335static void sdr_inc_reservation(IPMISdr *sdr)
336{
337 sdr->reservation++;
338 if (sdr->reservation == 0) {
339 sdr->reservation = 1;
340 }
341}
342
a2295f0a
CLG
343static int sdr_add_entry(IPMIBmcSim *ibs,
344 const struct ipmi_sdr_header *sdrh_entry,
8bfffbcc
CM
345 unsigned int len, uint16_t *recid)
346{
a2295f0a
CLG
347 struct ipmi_sdr_header *sdrh =
348 (struct ipmi_sdr_header *) &ibs->sdr.sdr[ibs->sdr.next_free];
349
350 if ((len < IPMI_SDR_HEADER_SIZE) || (len > 255)) {
8bfffbcc
CM
351 return 1;
352 }
353
a2295f0a 354 if (ipmi_sdr_length(sdrh_entry) != len) {
8bfffbcc
CM
355 return 1;
356 }
357
358 if (ibs->sdr.next_free + len > MAX_SDR_SIZE) {
359 ibs->sdr.overflow = 1;
360 return 1;
361 }
362
a2295f0a
CLG
363 memcpy(sdrh, sdrh_entry, len);
364 sdrh->rec_id[0] = ibs->sdr.next_rec_id & 0xff;
365 sdrh->rec_id[1] = (ibs->sdr.next_rec_id >> 8) & 0xff;
366 sdrh->sdr_version = 0x51; /* Conform to IPMI 1.5 spec */
8bfffbcc
CM
367
368 if (recid) {
369 *recid = ibs->sdr.next_rec_id;
370 }
371 ibs->sdr.next_rec_id++;
372 set_timestamp(ibs, ibs->sdr.last_addition);
373 ibs->sdr.next_free += len;
374 sdr_inc_reservation(&ibs->sdr);
375 return 0;
376}
377
378static int sdr_find_entry(IPMISdr *sdr, uint16_t recid,
379 unsigned int *retpos, uint16_t *nextrec)
380{
381 unsigned int pos = *retpos;
382
383 while (pos < sdr->next_free) {
a2295f0a
CLG
384 struct ipmi_sdr_header *sdrh =
385 (struct ipmi_sdr_header *) &sdr->sdr[pos];
386 uint16_t trec = ipmi_sdr_recid(sdrh);
387 unsigned int nextpos = pos + ipmi_sdr_length(sdrh);
8bfffbcc
CM
388
389 if (trec == recid) {
390 if (nextrec) {
391 if (nextpos >= sdr->next_free) {
392 *nextrec = 0xffff;
393 } else {
394 *nextrec = (sdr->sdr[nextpos] |
395 (sdr->sdr[nextpos + 1] << 8));
396 }
397 }
398 *retpos = pos;
399 return 0;
400 }
401 pos = nextpos;
402 }
403 return 1;
404}
405
406static void sel_inc_reservation(IPMISel *sel)
407{
408 sel->reservation++;
409 if (sel->reservation == 0) {
410 sel->reservation = 1;
411 }
412}
413
414/* Returns 1 if the SEL is full and can't hold the event. */
415static int sel_add_event(IPMIBmcSim *ibs, uint8_t *event)
416{
417 event[0] = 0xff;
418 event[1] = 0xff;
419 set_timestamp(ibs, event + 3);
420 if (ibs->sel.next_free == MAX_SEL_SIZE) {
421 ibs->sel.overflow = 1;
422 return 1;
423 }
424 event[0] = ibs->sel.next_free & 0xff;
425 event[1] = (ibs->sel.next_free >> 8) & 0xff;
426 memcpy(ibs->sel.last_addition, event + 3, 4);
427 memcpy(ibs->sel.sel[ibs->sel.next_free], event, 16);
428 ibs->sel.next_free++;
429 sel_inc_reservation(&ibs->sel);
430 return 0;
431}
432
433static int attn_set(IPMIBmcSim *ibs)
434{
435 return IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs)
436 || IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs)
437 || IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs);
438}
439
440static int attn_irq_enabled(IPMIBmcSim *ibs)
441{
442 return (IPMI_BMC_MSG_INTS_ON(ibs) && IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs))
443 || (IPMI_BMC_EVBUF_FULL_INT_ENABLED(ibs) &&
444 IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs));
445}
446
447static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert,
448 uint8_t evd1, uint8_t evd2, uint8_t evd3)
449{
450 IPMIInterface *s = ibs->parent.intf;
451 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
452 uint8_t evt[16];
453 IPMISensor *sens = ibs->sensors + sens_num;
454
455 if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) {
456 return;
457 }
458 if (!IPMI_SENSOR_GET_EVENTS_ON(sens)) {
459 return;
460 }
461
462 evt[2] = 0x2; /* System event record */
463 evt[7] = ibs->parent.slave_addr;
464 evt[8] = 0;
465 evt[9] = 0x04; /* Format version */
466 evt[10] = sens->sensor_type;
467 evt[11] = sens_num;
468 evt[12] = sens->evt_reading_type_code | (!!deassert << 7);
469 evt[13] = evd1;
470 evt[14] = evd2;
471 evt[15] = evd3;
472
473 if (IPMI_BMC_EVENT_LOG_ENABLED(ibs)) {
474 sel_add_event(ibs, evt);
475 }
476
477 if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) {
d13ada5d 478 return;
8bfffbcc
CM
479 }
480
481 memcpy(ibs->evtbuf, evt, 16);
482 ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
483 k->set_atn(s, 1, attn_irq_enabled(ibs));
8bfffbcc
CM
484}
485
486static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor,
487 unsigned int bit, unsigned int val,
488 uint8_t evd1, uint8_t evd2, uint8_t evd3)
489{
490 IPMISensor *sens;
491 uint16_t mask;
492
493 if (sensor >= MAX_SENSORS) {
494 return;
495 }
496 if (bit >= 16) {
497 return;
498 }
499
500 mask = (1 << bit);
501 sens = ibs->sensors + sensor;
502 if (val) {
503 sens->states |= mask & sens->states_suppt;
504 if (sens->assert_states & mask) {
505 return; /* Already asserted */
506 }
507 sens->assert_states |= mask & sens->assert_suppt;
508 if (sens->assert_enable & mask & sens->assert_states) {
509 /* Send an event on assert */
510 gen_event(ibs, sensor, 0, evd1, evd2, evd3);
511 }
512 } else {
513 sens->states &= ~(mask & sens->states_suppt);
514 if (sens->deassert_states & mask) {
515 return; /* Already deasserted */
516 }
517 sens->deassert_states |= mask & sens->deassert_suppt;
518 if (sens->deassert_enable & mask & sens->deassert_states) {
519 /* Send an event on deassert */
520 gen_event(ibs, sensor, 1, evd1, evd2, evd3);
521 }
522 }
523}
524
525static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s)
526{
527 unsigned int i, pos;
528 IPMISensor *sens;
529
530 for (i = 0; i < MAX_SENSORS; i++) {
531 memset(s->sensors + i, 0, sizeof(*sens));
532 }
533
534 pos = 0;
535 for (i = 0; !sdr_find_entry(&s->sdr, i, &pos, NULL); i++) {
a2295f0a
CLG
536 struct ipmi_sdr_compact *sdr =
537 (struct ipmi_sdr_compact *) &s->sdr.sdr[pos];
538 unsigned int len = sdr->header.rec_length;
8bfffbcc
CM
539
540 if (len < 20) {
541 continue;
542 }
a2295f0a 543 if (sdr->header.rec_type != IPMI_SDR_COMPACT_TYPE) {
8bfffbcc
CM
544 continue; /* Not a sensor SDR we set from */
545 }
546
73d60fa5 547 if (sdr->sensor_owner_number >= MAX_SENSORS) {
8bfffbcc
CM
548 continue;
549 }
a2295f0a 550 sens = s->sensors + sdr->sensor_owner_number;
8bfffbcc
CM
551
552 IPMI_SENSOR_SET_PRESENT(sens, 1);
a2295f0a
CLG
553 IPMI_SENSOR_SET_SCAN_ON(sens, (sdr->sensor_init >> 6) & 1);
554 IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr->sensor_init >> 5) & 1);
555 sens->assert_suppt = sdr->assert_mask[0] | (sdr->assert_mask[1] << 8);
556 sens->deassert_suppt =
557 sdr->deassert_mask[0] | (sdr->deassert_mask[1] << 8);
558 sens->states_suppt =
559 sdr->discrete_mask[0] | (sdr->discrete_mask[1] << 8);
560 sens->sensor_type = sdr->sensor_type;
561 sens->evt_reading_type_code = sdr->reading_type & 0x7f;
8bfffbcc
CM
562
563 /* Enable all the events that are supported. */
564 sens->assert_enable = sens->assert_suppt;
565 sens->deassert_enable = sens->deassert_suppt;
566 }
567}
568
569static int ipmi_register_netfn(IPMIBmcSim *s, unsigned int netfn,
570 const IPMINetfn *netfnd)
571{
93a53646 572 if ((netfn & 1) || (netfn >= MAX_NETFNS) || (s->netfns[netfn / 2])) {
8bfffbcc
CM
573 return -1;
574 }
575 s->netfns[netfn / 2] = netfnd;
576 return 0;
577}
578
4f298a4b
CLG
579static const IPMICmdHandler *ipmi_get_handler(IPMIBmcSim *ibs,
580 unsigned int netfn,
581 unsigned int cmd)
582{
583 const IPMICmdHandler *hdl;
584
585 if (netfn & 1 || netfn >= MAX_NETFNS || !ibs->netfns[netfn / 2]) {
586 return NULL;
587 }
588
589 if (cmd >= ibs->netfns[netfn / 2]->cmd_nums) {
590 return NULL;
591 }
592
593 hdl = &ibs->netfns[netfn / 2]->cmd_handlers[cmd];
594 if (!hdl->cmd_handler) {
595 return NULL;
596 }
597
598 return hdl;
599}
600
8bfffbcc
CM
601static void next_timeout(IPMIBmcSim *ibs)
602{
603 int64_t next;
604 if (ibs->watchdog_running) {
605 next = ibs->watchdog_expiry;
606 } else {
607 /* Wait a minute */
608 next = ipmi_getmonotime() + 60 * 1000000000LL;
609 }
610 timer_mod_ns(ibs->timer, next);
611}
612
613static void ipmi_sim_handle_command(IPMIBmc *b,
614 uint8_t *cmd, unsigned int cmd_len,
615 unsigned int max_cmd_len,
616 uint8_t msg_id)
617{
618 IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
619 IPMIInterface *s = ibs->parent.intf;
620 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
4f298a4b 621 const IPMICmdHandler *hdl;
a580d820 622 RspBuffer rsp = RSP_BUFFER_INITIALIZER;
8bfffbcc
CM
623
624 /* Set up the response, set the low bit of NETFN. */
625 /* Note that max_rsp_len must be at least 3 */
a580d820 626 if (sizeof(rsp.buffer) < 3) {
6acb971a 627 rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
d13ada5d
CLG
628 goto out;
629 }
630
a580d820
CLG
631 rsp_buffer_push(&rsp, cmd[0] | 0x04);
632 rsp_buffer_push(&rsp, cmd[1]);
633 rsp_buffer_push(&rsp, 0); /* Assume success */
8bfffbcc
CM
634
635 /* If it's too short or it was truncated, return an error. */
636 if (cmd_len < 2) {
6acb971a 637 rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
8bfffbcc
CM
638 goto out;
639 }
640 if (cmd_len > max_cmd_len) {
6acb971a 641 rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
8bfffbcc
CM
642 goto out;
643 }
644
645 if ((cmd[0] & 0x03) != 0) {
646 /* Only have stuff on LUN 0 */
6acb971a 647 rsp_buffer_set_error(&rsp, IPMI_CC_COMMAND_INVALID_FOR_LUN);
8bfffbcc
CM
648 goto out;
649 }
650
4f298a4b
CLG
651 hdl = ipmi_get_handler(ibs, cmd[0] >> 2, cmd[1]);
652 if (!hdl) {
6acb971a 653 rsp_buffer_set_error(&rsp, IPMI_CC_INVALID_CMD);
8bfffbcc
CM
654 goto out;
655 }
656
4f298a4b 657 if (cmd_len < hdl->cmd_len_min) {
6acb971a 658 rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
4f298a4b
CLG
659 goto out;
660 }
661
a580d820 662 hdl->cmd_handler(ibs, cmd, cmd_len, &rsp);
8bfffbcc
CM
663
664 out:
a580d820 665 k->handle_rsp(s, msg_id, rsp.buffer, rsp.len);
8bfffbcc
CM
666
667 next_timeout(ibs);
668}
669
670static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs)
671{
672 IPMIInterface *s = ibs->parent.intf;
673 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
674
675 if (!ibs->watchdog_running) {
676 goto out;
677 }
678
679 if (!ibs->watchdog_preaction_ran) {
680 switch (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs)) {
681 case IPMI_BMC_WATCHDOG_PRE_NMI:
682 ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
683 k->do_hw_op(s, IPMI_SEND_NMI, 0);
684 sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
685 0xc8, (2 << 4) | 0xf, 0xff);
686 break;
687
688 case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
689 ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
690 k->set_atn(s, 1, attn_irq_enabled(ibs));
691 sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
692 0xc8, (3 << 4) | 0xf, 0xff);
693 break;
694
695 default:
696 goto do_full_expiry;
697 }
698
699 ibs->watchdog_preaction_ran = 1;
700 /* Issued the pretimeout, do the rest of the timeout now. */
701 ibs->watchdog_expiry = ipmi_getmonotime();
702 ibs->watchdog_expiry += ibs->watchdog_pretimeout * 1000000000LL;
703 goto out;
704 }
705
706 do_full_expiry:
707 ibs->watchdog_running = 0; /* Stop the watchdog on a timeout */
708 ibs->watchdog_expired |= (1 << IPMI_BMC_WATCHDOG_GET_USE(ibs));
709 switch (IPMI_BMC_WATCHDOG_GET_ACTION(ibs)) {
710 case IPMI_BMC_WATCHDOG_ACTION_NONE:
711 sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 0, 1,
712 0xc0, ibs->watchdog_use & 0xf, 0xff);
713 break;
714
715 case IPMI_BMC_WATCHDOG_ACTION_RESET:
716 sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 1, 1,
717 0xc1, ibs->watchdog_use & 0xf, 0xff);
718 k->do_hw_op(s, IPMI_RESET_CHASSIS, 0);
719 break;
720
721 case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
722 sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
723 0xc2, ibs->watchdog_use & 0xf, 0xff);
724 k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0);
725 break;
726
727 case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
728 sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
729 0xc3, ibs->watchdog_use & 0xf, 0xff);
730 k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0);
731 break;
732 }
733
734 out:
735 next_timeout(ibs);
736}
737
738static void chassis_capabilities(IPMIBmcSim *ibs,
739 uint8_t *cmd, unsigned int cmd_len,
a580d820 740 RspBuffer *rsp)
8bfffbcc 741{
a580d820
CLG
742 rsp_buffer_push(rsp, 0);
743 rsp_buffer_push(rsp, ibs->parent.slave_addr);
744 rsp_buffer_push(rsp, ibs->parent.slave_addr);
745 rsp_buffer_push(rsp, ibs->parent.slave_addr);
746 rsp_buffer_push(rsp, ibs->parent.slave_addr);
8bfffbcc
CM
747}
748
749static void chassis_status(IPMIBmcSim *ibs,
750 uint8_t *cmd, unsigned int cmd_len,
a580d820 751 RspBuffer *rsp)
8bfffbcc 752{
a580d820
CLG
753 rsp_buffer_push(rsp, 0x61); /* Unknown power restore, power is on */
754 rsp_buffer_push(rsp, 0);
755 rsp_buffer_push(rsp, 0);
756 rsp_buffer_push(rsp, 0);
8bfffbcc
CM
757}
758
759static void chassis_control(IPMIBmcSim *ibs,
760 uint8_t *cmd, unsigned int cmd_len,
a580d820 761 RspBuffer *rsp)
8bfffbcc
CM
762{
763 IPMIInterface *s = ibs->parent.intf;
764 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
765
8bfffbcc
CM
766 switch (cmd[2] & 0xf) {
767 case 0: /* power down */
6acb971a 768 rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0));
8bfffbcc
CM
769 break;
770 case 1: /* power up */
6acb971a 771 rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERON_CHASSIS, 0));
8bfffbcc
CM
772 break;
773 case 2: /* power cycle */
6acb971a 774 rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0));
8bfffbcc
CM
775 break;
776 case 3: /* hard reset */
6acb971a 777 rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 0));
8bfffbcc
CM
778 break;
779 case 4: /* pulse diagnostic interrupt */
6acb971a 780 rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_PULSE_DIAG_IRQ, 0));
8bfffbcc
CM
781 break;
782 case 5: /* soft shutdown via ACPI by overtemp emulation */
6acb971a
CLG
783 rsp_buffer_set_error(rsp, k->do_hw_op(s,
784 IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 0));
8bfffbcc
CM
785 break;
786 default:
6acb971a 787 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
d13ada5d 788 return;
8bfffbcc 789 }
8bfffbcc
CM
790}
791
b7088392
CLG
792static void chassis_get_sys_restart_cause(IPMIBmcSim *ibs,
793 uint8_t *cmd, unsigned int cmd_len,
a580d820
CLG
794 RspBuffer *rsp)
795
b7088392 796{
a580d820
CLG
797 rsp_buffer_push(rsp, ibs->restart_cause & 0xf); /* Restart Cause */
798 rsp_buffer_push(rsp, 0); /* Channel 0 */
b7088392
CLG
799}
800
8bfffbcc
CM
801static void get_device_id(IPMIBmcSim *ibs,
802 uint8_t *cmd, unsigned int cmd_len,
a580d820 803 RspBuffer *rsp)
8bfffbcc 804{
a580d820
CLG
805 rsp_buffer_push(rsp, ibs->device_id);
806 rsp_buffer_push(rsp, ibs->device_rev & 0xf);
807 rsp_buffer_push(rsp, ibs->fwrev1 & 0x7f);
808 rsp_buffer_push(rsp, ibs->fwrev2);
809 rsp_buffer_push(rsp, ibs->ipmi_version);
810 rsp_buffer_push(rsp, 0x07); /* sensor, SDR, and SEL. */
811 rsp_buffer_push(rsp, ibs->mfg_id[0]);
812 rsp_buffer_push(rsp, ibs->mfg_id[1]);
813 rsp_buffer_push(rsp, ibs->mfg_id[2]);
814 rsp_buffer_push(rsp, ibs->product_id[0]);
815 rsp_buffer_push(rsp, ibs->product_id[1]);
8bfffbcc
CM
816}
817
818static void set_global_enables(IPMIBmcSim *ibs, uint8_t val)
819{
820 IPMIInterface *s = ibs->parent.intf;
821 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
822 bool irqs_on;
823
824 ibs->bmc_global_enables = val;
825
826 irqs_on = val & (IPMI_BMC_EVBUF_FULL_INT_BIT |
827 IPMI_BMC_RCV_MSG_QUEUE_INT_BIT);
828
829 k->set_irq_enable(s, irqs_on);
830}
831
832static void cold_reset(IPMIBmcSim *ibs,
833 uint8_t *cmd, unsigned int cmd_len,
a580d820 834 RspBuffer *rsp)
8bfffbcc
CM
835{
836 IPMIInterface *s = ibs->parent.intf;
837 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
838
839 /* Disable all interrupts */
840 set_global_enables(ibs, 1 << IPMI_BMC_EVENT_LOG_BIT);
841
842 if (k->reset) {
843 k->reset(s, true);
844 }
845}
846
847static void warm_reset(IPMIBmcSim *ibs,
848 uint8_t *cmd, unsigned int cmd_len,
a580d820 849 RspBuffer *rsp)
8bfffbcc
CM
850{
851 IPMIInterface *s = ibs->parent.intf;
852 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
853
854 if (k->reset) {
855 k->reset(s, false);
856 }
857}
52ba4d50 858static void set_acpi_power_state(IPMIBmcSim *ibs,
a580d820
CLG
859 uint8_t *cmd, unsigned int cmd_len,
860 RspBuffer *rsp)
52ba4d50 861{
52ba4d50
CLG
862 ibs->acpi_power_state[0] = cmd[2];
863 ibs->acpi_power_state[1] = cmd[3];
864}
865
866static void get_acpi_power_state(IPMIBmcSim *ibs,
a580d820
CLG
867 uint8_t *cmd, unsigned int cmd_len,
868 RspBuffer *rsp)
52ba4d50 869{
a580d820
CLG
870 rsp_buffer_push(rsp, ibs->acpi_power_state[0]);
871 rsp_buffer_push(rsp, ibs->acpi_power_state[1]);
52ba4d50
CLG
872}
873
874static void get_device_guid(IPMIBmcSim *ibs,
a580d820
CLG
875 uint8_t *cmd, unsigned int cmd_len,
876 RspBuffer *rsp)
52ba4d50
CLG
877{
878 unsigned int i;
879
880 for (i = 0; i < 16; i++) {
a580d820 881 rsp_buffer_push(rsp, ibs->uuid[i]);
52ba4d50
CLG
882 }
883}
8bfffbcc
CM
884
885static void set_bmc_global_enables(IPMIBmcSim *ibs,
886 uint8_t *cmd, unsigned int cmd_len,
a580d820 887 RspBuffer *rsp)
8bfffbcc 888{
8bfffbcc 889 set_global_enables(ibs, cmd[2]);
8bfffbcc
CM
890}
891
892static void get_bmc_global_enables(IPMIBmcSim *ibs,
893 uint8_t *cmd, unsigned int cmd_len,
a580d820 894 RspBuffer *rsp)
8bfffbcc 895{
a580d820 896 rsp_buffer_push(rsp, ibs->bmc_global_enables);
8bfffbcc
CM
897}
898
899static void clr_msg_flags(IPMIBmcSim *ibs,
900 uint8_t *cmd, unsigned int cmd_len,
a580d820 901 RspBuffer *rsp)
8bfffbcc
CM
902{
903 IPMIInterface *s = ibs->parent.intf;
904 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
905
8bfffbcc
CM
906 ibs->msg_flags &= ~cmd[2];
907 k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
8bfffbcc
CM
908}
909
910static void get_msg_flags(IPMIBmcSim *ibs,
911 uint8_t *cmd, unsigned int cmd_len,
a580d820 912 RspBuffer *rsp)
8bfffbcc 913{
a580d820 914 rsp_buffer_push(rsp, ibs->msg_flags);
8bfffbcc
CM
915}
916
917static void read_evt_msg_buf(IPMIBmcSim *ibs,
918 uint8_t *cmd, unsigned int cmd_len,
a580d820 919 RspBuffer *rsp)
8bfffbcc
CM
920{
921 IPMIInterface *s = ibs->parent.intf;
922 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
923 unsigned int i;
924
925 if (!(ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL)) {
6acb971a 926 rsp_buffer_set_error(rsp, 0x80);
d13ada5d 927 return;
8bfffbcc
CM
928 }
929 for (i = 0; i < 16; i++) {
a580d820 930 rsp_buffer_push(rsp, ibs->evtbuf[i]);
8bfffbcc
CM
931 }
932 ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
933 k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
8bfffbcc
CM
934}
935
936static void get_msg(IPMIBmcSim *ibs,
937 uint8_t *cmd, unsigned int cmd_len,
a580d820 938 RspBuffer *rsp)
8bfffbcc
CM
939{
940 IPMIRcvBufEntry *msg;
941
8bfffbcc 942 if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
6acb971a 943 rsp_buffer_set_error(rsp, 0x80); /* Queue empty */
8bfffbcc
CM
944 goto out;
945 }
a580d820 946 rsp_buffer_push(rsp, 0); /* Channel 0 */
8bfffbcc 947 msg = QTAILQ_FIRST(&ibs->rcvbufs);
a580d820 948 rsp_buffer_pushmore(rsp, msg->buf, msg->len);
8bfffbcc
CM
949 QTAILQ_REMOVE(&ibs->rcvbufs, msg, entry);
950 g_free(msg);
951
952 if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
953 IPMIInterface *s = ibs->parent.intf;
954 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
955
956 ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
957 k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
958 }
959
d13ada5d 960out:
8bfffbcc
CM
961 return;
962}
963
964static unsigned char
965ipmb_checksum(unsigned char *data, int size, unsigned char csum)
966{
967 for (; size > 0; size--, data++) {
968 csum += *data;
969 }
970
971 return -csum;
972}
973
974static void send_msg(IPMIBmcSim *ibs,
975 uint8_t *cmd, unsigned int cmd_len,
a580d820 976 RspBuffer *rsp)
8bfffbcc
CM
977{
978 IPMIInterface *s = ibs->parent.intf;
979 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
980 IPMIRcvBufEntry *msg;
981 uint8_t *buf;
982 uint8_t netfn, rqLun, rsLun, rqSeq;
983
8bfffbcc
CM
984 if (cmd[2] != 0) {
985 /* We only handle channel 0 with no options */
6acb971a 986 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
d13ada5d 987 return;
8bfffbcc
CM
988 }
989
4f298a4b 990 if (cmd_len < 10) {
6acb971a 991 rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
4f298a4b
CLG
992 return;
993 }
994
8bfffbcc
CM
995 if (cmd[3] != 0x40) {
996 /* We only emulate a MC at address 0x40. */
6acb971a 997 rsp_buffer_set_error(rsp, 0x83); /* NAK on write */
d13ada5d 998 return;
8bfffbcc
CM
999 }
1000
1001 cmd += 3; /* Skip the header. */
1002 cmd_len -= 3;
1003
1004 /*
1005 * At this point we "send" the message successfully. Any error will
1006 * be returned in the response.
1007 */
1008 if (ipmb_checksum(cmd, cmd_len, 0) != 0 ||
1009 cmd[3] != 0x20) { /* Improper response address */
d13ada5d 1010 return; /* No response */
8bfffbcc
CM
1011 }
1012
1013 netfn = cmd[1] >> 2;
1014 rqLun = cmd[4] & 0x3;
1015 rsLun = cmd[1] & 0x3;
1016 rqSeq = cmd[4] >> 2;
1017
1018 if (rqLun != 2) {
1019 /* We only support LUN 2 coming back to us. */
d13ada5d 1020 return;
8bfffbcc
CM
1021 }
1022
1023 msg = g_malloc(sizeof(*msg));
1024 msg->buf[0] = ((netfn | 1) << 2) | rqLun; /* NetFN, and make a response */
1025 msg->buf[1] = ipmb_checksum(msg->buf, 1, 0);
1026 msg->buf[2] = cmd[0]; /* rsSA */
1027 msg->buf[3] = (rqSeq << 2) | rsLun;
1028 msg->buf[4] = cmd[5]; /* Cmd */
1029 msg->buf[5] = 0; /* Completion Code */
1030 msg->len = 6;
1031
1032 if ((cmd[1] >> 2) != IPMI_NETFN_APP || cmd[5] != IPMI_CMD_GET_DEVICE_ID) {
1033 /* Not a command we handle. */
1034 msg->buf[5] = IPMI_CC_INVALID_CMD;
1035 goto end_msg;
1036 }
1037
1038 buf = msg->buf + msg->len; /* After the CC */
1039 buf[0] = 0;
1040 buf[1] = 0;
1041 buf[2] = 0;
1042 buf[3] = 0;
1043 buf[4] = 0x51;
1044 buf[5] = 0;
1045 buf[6] = 0;
1046 buf[7] = 0;
1047 buf[8] = 0;
1048 buf[9] = 0;
1049 buf[10] = 0;
1050 msg->len += 11;
1051
1052 end_msg:
1053 msg->buf[msg->len] = ipmb_checksum(msg->buf, msg->len, 0);
1054 msg->len++;
8bfffbcc
CM
1055 QTAILQ_INSERT_TAIL(&ibs->rcvbufs, msg, entry);
1056 ibs->msg_flags |= IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
1057 k->set_atn(s, 1, attn_irq_enabled(ibs));
8bfffbcc
CM
1058}
1059
1060static void do_watchdog_reset(IPMIBmcSim *ibs)
1061{
1062 if (IPMI_BMC_WATCHDOG_GET_ACTION(ibs) ==
1063 IPMI_BMC_WATCHDOG_ACTION_NONE) {
1064 ibs->watchdog_running = 0;
1065 return;
1066 }
1067 ibs->watchdog_preaction_ran = 0;
1068
1069
1070 /* Timeout is in tenths of a second, offset is in seconds */
1071 ibs->watchdog_expiry = ipmi_getmonotime();
1072 ibs->watchdog_expiry += ibs->watchdog_timeout * 100000000LL;
1073 if (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs) != IPMI_BMC_WATCHDOG_PRE_NONE) {
1074 ibs->watchdog_expiry -= ibs->watchdog_pretimeout * 1000000000LL;
1075 }
1076 ibs->watchdog_running = 1;
1077}
1078
1079static void reset_watchdog_timer(IPMIBmcSim *ibs,
1080 uint8_t *cmd, unsigned int cmd_len,
a580d820 1081 RspBuffer *rsp)
8bfffbcc
CM
1082{
1083 if (!ibs->watchdog_initialized) {
6acb971a 1084 rsp_buffer_set_error(rsp, 0x80);
d13ada5d 1085 return;
8bfffbcc
CM
1086 }
1087 do_watchdog_reset(ibs);
8bfffbcc
CM
1088}
1089
1090static void set_watchdog_timer(IPMIBmcSim *ibs,
1091 uint8_t *cmd, unsigned int cmd_len,
a580d820 1092 RspBuffer *rsp)
8bfffbcc
CM
1093{
1094 IPMIInterface *s = ibs->parent.intf;
1095 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
1096 unsigned int val;
1097
8bfffbcc
CM
1098 val = cmd[2] & 0x7; /* Validate use */
1099 if (val == 0 || val > 5) {
6acb971a 1100 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
d13ada5d 1101 return;
8bfffbcc
CM
1102 }
1103 val = cmd[3] & 0x7; /* Validate action */
1104 switch (val) {
1105 case IPMI_BMC_WATCHDOG_ACTION_NONE:
1106 break;
1107
1108 case IPMI_BMC_WATCHDOG_ACTION_RESET:
6acb971a 1109 rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 1));
8bfffbcc
CM
1110 break;
1111
1112 case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
6acb971a 1113 rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 1));
8bfffbcc
CM
1114 break;
1115
1116 case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
6acb971a 1117 rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 1));
8bfffbcc
CM
1118 break;
1119
1120 default:
6acb971a 1121 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
8bfffbcc 1122 }
a580d820 1123 if (rsp->buffer[2]) {
6acb971a 1124 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
d13ada5d 1125 return;
8bfffbcc
CM
1126 }
1127
1128 val = (cmd[3] >> 4) & 0x7; /* Validate preaction */
1129 switch (val) {
1130 case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
1131 case IPMI_BMC_WATCHDOG_PRE_NONE:
1132 break;
1133
1134 case IPMI_BMC_WATCHDOG_PRE_NMI:
1135 if (!k->do_hw_op(s, IPMI_SEND_NMI, 1)) {
1136 /* NMI not supported. */
6acb971a 1137 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
d13ada5d 1138 return;
8bfffbcc 1139 }
37eebb86
CM
1140 break;
1141
8bfffbcc
CM
1142 default:
1143 /* We don't support PRE_SMI */
6acb971a 1144 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
d13ada5d 1145 return;
8bfffbcc
CM
1146 }
1147
1148 ibs->watchdog_initialized = 1;
1149 ibs->watchdog_use = cmd[2] & IPMI_BMC_WATCHDOG_USE_MASK;
1150 ibs->watchdog_action = cmd[3] & IPMI_BMC_WATCHDOG_ACTION_MASK;
1151 ibs->watchdog_pretimeout = cmd[4];
1152 ibs->watchdog_expired &= ~cmd[5];
1153 ibs->watchdog_timeout = cmd[6] | (((uint16_t) cmd[7]) << 8);
1154 if (ibs->watchdog_running & IPMI_BMC_WATCHDOG_GET_DONT_STOP(ibs)) {
1155 do_watchdog_reset(ibs);
1156 } else {
1157 ibs->watchdog_running = 0;
1158 }
8bfffbcc
CM
1159}
1160
1161static void get_watchdog_timer(IPMIBmcSim *ibs,
1162 uint8_t *cmd, unsigned int cmd_len,
a580d820 1163 RspBuffer *rsp)
8bfffbcc 1164{
a580d820
CLG
1165 rsp_buffer_push(rsp, ibs->watchdog_use);
1166 rsp_buffer_push(rsp, ibs->watchdog_action);
1167 rsp_buffer_push(rsp, ibs->watchdog_pretimeout);
1168 rsp_buffer_push(rsp, ibs->watchdog_expired);
8bfffbcc
CM
1169 if (ibs->watchdog_running) {
1170 long timeout;
1171 timeout = ((ibs->watchdog_expiry - ipmi_getmonotime() + 50000000)
1172 / 100000000);
a580d820
CLG
1173 rsp_buffer_push(rsp, timeout & 0xff);
1174 rsp_buffer_push(rsp, (timeout >> 8) & 0xff);
8bfffbcc 1175 } else {
a580d820
CLG
1176 rsp_buffer_push(rsp, 0);
1177 rsp_buffer_push(rsp, 0);
8bfffbcc 1178 }
8bfffbcc
CM
1179}
1180
1181static void get_sdr_rep_info(IPMIBmcSim *ibs,
1182 uint8_t *cmd, unsigned int cmd_len,
a580d820 1183 RspBuffer *rsp)
8bfffbcc
CM
1184{
1185 unsigned int i;
1186
a580d820
CLG
1187 rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 spec */
1188 rsp_buffer_push(rsp, ibs->sdr.next_rec_id & 0xff);
1189 rsp_buffer_push(rsp, (ibs->sdr.next_rec_id >> 8) & 0xff);
1190 rsp_buffer_push(rsp, (MAX_SDR_SIZE - ibs->sdr.next_free) & 0xff);
1191 rsp_buffer_push(rsp, ((MAX_SDR_SIZE - ibs->sdr.next_free) >> 8) & 0xff);
8bfffbcc 1192 for (i = 0; i < 4; i++) {
a580d820 1193 rsp_buffer_push(rsp, ibs->sdr.last_addition[i]);
8bfffbcc
CM
1194 }
1195 for (i = 0; i < 4; i++) {
a580d820 1196 rsp_buffer_push(rsp, ibs->sdr.last_clear[i]);
8bfffbcc
CM
1197 }
1198 /* Only modal support, reserve supported */
a580d820 1199 rsp_buffer_push(rsp, (ibs->sdr.overflow << 7) | 0x22);
8bfffbcc
CM
1200}
1201
1202static void reserve_sdr_rep(IPMIBmcSim *ibs,
1203 uint8_t *cmd, unsigned int cmd_len,
a580d820 1204 RspBuffer *rsp)
8bfffbcc 1205{
a580d820
CLG
1206 rsp_buffer_push(rsp, ibs->sdr.reservation & 0xff);
1207 rsp_buffer_push(rsp, (ibs->sdr.reservation >> 8) & 0xff);
8bfffbcc
CM
1208}
1209
1210static void get_sdr(IPMIBmcSim *ibs,
1211 uint8_t *cmd, unsigned int cmd_len,
a580d820 1212 RspBuffer *rsp)
8bfffbcc
CM
1213{
1214 unsigned int pos;
1215 uint16_t nextrec;
a2295f0a 1216 struct ipmi_sdr_header *sdrh;
8bfffbcc 1217
8bfffbcc 1218 if (cmd[6]) {
7f996411 1219 if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) {
6acb971a 1220 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
7f996411
CLG
1221 return;
1222 }
8bfffbcc 1223 }
7f996411 1224
8bfffbcc
CM
1225 pos = 0;
1226 if (sdr_find_entry(&ibs->sdr, cmd[4] | (cmd[5] << 8),
1227 &pos, &nextrec)) {
6acb971a 1228 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
d13ada5d 1229 return;
8bfffbcc 1230 }
a2295f0a
CLG
1231
1232 sdrh = (struct ipmi_sdr_header *) &ibs->sdr.sdr[pos];
1233
1234 if (cmd[6] > ipmi_sdr_length(sdrh)) {
6acb971a 1235 rsp_buffer_set_error(rsp, IPMI_CC_PARM_OUT_OF_RANGE);
d13ada5d 1236 return;
8bfffbcc
CM
1237 }
1238
a580d820
CLG
1239 rsp_buffer_push(rsp, nextrec & 0xff);
1240 rsp_buffer_push(rsp, (nextrec >> 8) & 0xff);
8bfffbcc
CM
1241
1242 if (cmd[7] == 0xff) {
a2295f0a 1243 cmd[7] = ipmi_sdr_length(sdrh) - cmd[6];
8bfffbcc
CM
1244 }
1245
a580d820 1246 if ((cmd[7] + rsp->len) > sizeof(rsp->buffer)) {
6acb971a 1247 rsp_buffer_set_error(rsp, IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES);
d13ada5d 1248 return;
8bfffbcc 1249 }
a580d820
CLG
1250
1251 rsp_buffer_pushmore(rsp, ibs->sdr.sdr + pos + cmd[6], cmd[7]);
8bfffbcc
CM
1252}
1253
1254static void add_sdr(IPMIBmcSim *ibs,
1255 uint8_t *cmd, unsigned int cmd_len,
a580d820 1256 RspBuffer *rsp)
8bfffbcc
CM
1257{
1258 uint16_t recid;
a2295f0a 1259 struct ipmi_sdr_header *sdrh = (struct ipmi_sdr_header *) cmd + 2;
8bfffbcc 1260
a2295f0a 1261 if (sdr_add_entry(ibs, sdrh, cmd_len - 2, &recid)) {
6acb971a 1262 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
d13ada5d 1263 return;
8bfffbcc 1264 }
a580d820
CLG
1265 rsp_buffer_push(rsp, recid & 0xff);
1266 rsp_buffer_push(rsp, (recid >> 8) & 0xff);
8bfffbcc
CM
1267}
1268
1269static void clear_sdr_rep(IPMIBmcSim *ibs,
1270 uint8_t *cmd, unsigned int cmd_len,
a580d820 1271 RspBuffer *rsp)
8bfffbcc 1272{
7f996411 1273 if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) {
6acb971a 1274 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
7f996411
CLG
1275 return;
1276 }
1277
8bfffbcc 1278 if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
6acb971a 1279 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
d13ada5d 1280 return;
8bfffbcc
CM
1281 }
1282 if (cmd[7] == 0xaa) {
1283 ibs->sdr.next_free = 0;
1284 ibs->sdr.overflow = 0;
1285 set_timestamp(ibs, ibs->sdr.last_clear);
a580d820 1286 rsp_buffer_push(rsp, 1); /* Erasure complete */
8bfffbcc
CM
1287 sdr_inc_reservation(&ibs->sdr);
1288 } else if (cmd[7] == 0) {
a580d820 1289 rsp_buffer_push(rsp, 1); /* Erasure complete */
8bfffbcc 1290 } else {
6acb971a 1291 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
d13ada5d 1292 return;
8bfffbcc 1293 }
8bfffbcc
CM
1294}
1295
1296static void get_sel_info(IPMIBmcSim *ibs,
1297 uint8_t *cmd, unsigned int cmd_len,
a580d820 1298 RspBuffer *rsp)
8bfffbcc
CM
1299{
1300 unsigned int i, val;
1301
a580d820
CLG
1302 rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 */
1303 rsp_buffer_push(rsp, ibs->sel.next_free & 0xff);
1304 rsp_buffer_push(rsp, (ibs->sel.next_free >> 8) & 0xff);
8bfffbcc 1305 val = (MAX_SEL_SIZE - ibs->sel.next_free) * 16;
a580d820
CLG
1306 rsp_buffer_push(rsp, val & 0xff);
1307 rsp_buffer_push(rsp, (val >> 8) & 0xff);
8bfffbcc 1308 for (i = 0; i < 4; i++) {
a580d820 1309 rsp_buffer_push(rsp, ibs->sel.last_addition[i]);
8bfffbcc
CM
1310 }
1311 for (i = 0; i < 4; i++) {
a580d820 1312 rsp_buffer_push(rsp, ibs->sel.last_clear[i]);
8bfffbcc
CM
1313 }
1314 /* Only support Reserve SEL */
a580d820 1315 rsp_buffer_push(rsp, (ibs->sel.overflow << 7) | 0x02);
8bfffbcc
CM
1316}
1317
1318static void reserve_sel(IPMIBmcSim *ibs,
1319 uint8_t *cmd, unsigned int cmd_len,
a580d820 1320 RspBuffer *rsp)
8bfffbcc 1321{
a580d820
CLG
1322 rsp_buffer_push(rsp, ibs->sel.reservation & 0xff);
1323 rsp_buffer_push(rsp, (ibs->sel.reservation >> 8) & 0xff);
8bfffbcc
CM
1324}
1325
1326static void get_sel_entry(IPMIBmcSim *ibs,
1327 uint8_t *cmd, unsigned int cmd_len,
a580d820 1328 RspBuffer *rsp)
8bfffbcc
CM
1329{
1330 unsigned int val;
1331
8bfffbcc 1332 if (cmd[6]) {
7f996411 1333 if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) {
6acb971a 1334 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
7f996411
CLG
1335 return;
1336 }
8bfffbcc
CM
1337 }
1338 if (ibs->sel.next_free == 0) {
6acb971a 1339 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
d13ada5d 1340 return;
8bfffbcc
CM
1341 }
1342 if (cmd[6] > 15) {
6acb971a 1343 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
d13ada5d 1344 return;
8bfffbcc
CM
1345 }
1346 if (cmd[7] == 0xff) {
1347 cmd[7] = 16;
1348 } else if ((cmd[7] + cmd[6]) > 16) {
6acb971a 1349 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
d13ada5d 1350 return;
8bfffbcc
CM
1351 } else {
1352 cmd[7] += cmd[6];
1353 }
1354
1355 val = cmd[4] | (cmd[5] << 8);
1356 if (val == 0xffff) {
1357 val = ibs->sel.next_free - 1;
1358 } else if (val >= ibs->sel.next_free) {
6acb971a 1359 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
d13ada5d 1360 return;
8bfffbcc
CM
1361 }
1362 if ((val + 1) == ibs->sel.next_free) {
a580d820
CLG
1363 rsp_buffer_push(rsp, 0xff);
1364 rsp_buffer_push(rsp, 0xff);
8bfffbcc 1365 } else {
a580d820
CLG
1366 rsp_buffer_push(rsp, (val + 1) & 0xff);
1367 rsp_buffer_push(rsp, ((val + 1) >> 8) & 0xff);
8bfffbcc
CM
1368 }
1369 for (; cmd[6] < cmd[7]; cmd[6]++) {
a580d820 1370 rsp_buffer_push(rsp, ibs->sel.sel[val][cmd[6]]);
8bfffbcc 1371 }
8bfffbcc
CM
1372}
1373
1374static void add_sel_entry(IPMIBmcSim *ibs,
1375 uint8_t *cmd, unsigned int cmd_len,
a580d820 1376 RspBuffer *rsp)
8bfffbcc 1377{
8bfffbcc 1378 if (sel_add_event(ibs, cmd + 2)) {
6acb971a 1379 rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE);
d13ada5d 1380 return;
8bfffbcc
CM
1381 }
1382 /* sel_add_event fills in the record number. */
a580d820
CLG
1383 rsp_buffer_push(rsp, cmd[2]);
1384 rsp_buffer_push(rsp, cmd[3]);
8bfffbcc
CM
1385}
1386
1387static void clear_sel(IPMIBmcSim *ibs,
1388 uint8_t *cmd, unsigned int cmd_len,
a580d820 1389 RspBuffer *rsp)
8bfffbcc 1390{
7f996411 1391 if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) {
6acb971a 1392 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
7f996411
CLG
1393 return;
1394 }
1395
8bfffbcc 1396 if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
6acb971a 1397 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
d13ada5d 1398 return;
8bfffbcc
CM
1399 }
1400 if (cmd[7] == 0xaa) {
1401 ibs->sel.next_free = 0;
1402 ibs->sel.overflow = 0;
1403 set_timestamp(ibs, ibs->sdr.last_clear);
a580d820 1404 rsp_buffer_push(rsp, 1); /* Erasure complete */
8bfffbcc
CM
1405 sel_inc_reservation(&ibs->sel);
1406 } else if (cmd[7] == 0) {
a580d820 1407 rsp_buffer_push(rsp, 1); /* Erasure complete */
8bfffbcc 1408 } else {
6acb971a 1409 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
d13ada5d 1410 return;
8bfffbcc 1411 }
8bfffbcc
CM
1412}
1413
1414static void get_sel_time(IPMIBmcSim *ibs,
1415 uint8_t *cmd, unsigned int cmd_len,
a580d820 1416 RspBuffer *rsp)
8bfffbcc
CM
1417{
1418 uint32_t val;
1419 struct ipmi_time now;
1420
1421 ipmi_gettime(&now);
1422 val = now.tv_sec + ibs->sel.time_offset;
a580d820
CLG
1423 rsp_buffer_push(rsp, val & 0xff);
1424 rsp_buffer_push(rsp, (val >> 8) & 0xff);
1425 rsp_buffer_push(rsp, (val >> 16) & 0xff);
1426 rsp_buffer_push(rsp, (val >> 24) & 0xff);
8bfffbcc
CM
1427}
1428
1429static void set_sel_time(IPMIBmcSim *ibs,
1430 uint8_t *cmd, unsigned int cmd_len,
a580d820 1431 RspBuffer *rsp)
8bfffbcc
CM
1432{
1433 uint32_t val;
1434 struct ipmi_time now;
1435
8bfffbcc
CM
1436 val = cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24);
1437 ipmi_gettime(&now);
1438 ibs->sel.time_offset = now.tv_sec - ((long) val);
8bfffbcc
CM
1439}
1440
1441static void set_sensor_evt_enable(IPMIBmcSim *ibs,
1442 uint8_t *cmd, unsigned int cmd_len,
a580d820 1443 RspBuffer *rsp)
8bfffbcc
CM
1444{
1445 IPMISensor *sens;
1446
73d60fa5 1447 if ((cmd[2] >= MAX_SENSORS) ||
8bfffbcc 1448 !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
6acb971a 1449 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
d13ada5d 1450 return;
8bfffbcc
CM
1451 }
1452 sens = ibs->sensors + cmd[2];
1453 switch ((cmd[3] >> 4) & 0x3) {
1454 case 0: /* Do not change */
1455 break;
1456 case 1: /* Enable bits */
1457 if (cmd_len > 4) {
1458 sens->assert_enable |= cmd[4];
1459 }
1460 if (cmd_len > 5) {
1461 sens->assert_enable |= cmd[5] << 8;
1462 }
1463 if (cmd_len > 6) {
1464 sens->deassert_enable |= cmd[6];
1465 }
1466 if (cmd_len > 7) {
1467 sens->deassert_enable |= cmd[7] << 8;
1468 }
1469 break;
1470 case 2: /* Disable bits */
1471 if (cmd_len > 4) {
1472 sens->assert_enable &= ~cmd[4];
1473 }
1474 if (cmd_len > 5) {
1475 sens->assert_enable &= ~(cmd[5] << 8);
1476 }
1477 if (cmd_len > 6) {
1478 sens->deassert_enable &= ~cmd[6];
1479 }
1480 if (cmd_len > 7) {
1481 sens->deassert_enable &= ~(cmd[7] << 8);
1482 }
1483 break;
1484 case 3:
6acb971a 1485 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
d13ada5d 1486 return;
8bfffbcc
CM
1487 }
1488 IPMI_SENSOR_SET_RET_STATUS(sens, cmd[3]);
8bfffbcc
CM
1489}
1490
1491static void get_sensor_evt_enable(IPMIBmcSim *ibs,
1492 uint8_t *cmd, unsigned int cmd_len,
a580d820 1493 RspBuffer *rsp)
8bfffbcc
CM
1494{
1495 IPMISensor *sens;
1496
73d60fa5 1497 if ((cmd[2] >= MAX_SENSORS) ||
8bfffbcc 1498 !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
6acb971a 1499 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
d13ada5d 1500 return;
8bfffbcc
CM
1501 }
1502 sens = ibs->sensors + cmd[2];
a580d820
CLG
1503 rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1504 rsp_buffer_push(rsp, sens->assert_enable & 0xff);
1505 rsp_buffer_push(rsp, (sens->assert_enable >> 8) & 0xff);
1506 rsp_buffer_push(rsp, sens->deassert_enable & 0xff);
1507 rsp_buffer_push(rsp, (sens->deassert_enable >> 8) & 0xff);
8bfffbcc
CM
1508}
1509
1510static void rearm_sensor_evts(IPMIBmcSim *ibs,
1511 uint8_t *cmd, unsigned int cmd_len,
a580d820 1512 RspBuffer *rsp)
8bfffbcc
CM
1513{
1514 IPMISensor *sens;
1515
73d60fa5 1516 if ((cmd[2] >= MAX_SENSORS) ||
8bfffbcc 1517 !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
6acb971a 1518 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
d13ada5d 1519 return;
8bfffbcc
CM
1520 }
1521 sens = ibs->sensors + cmd[2];
1522
1523 if ((cmd[3] & 0x80) == 0) {
1524 /* Just clear everything */
1525 sens->states = 0;
d13ada5d 1526 return;
8bfffbcc 1527 }
8bfffbcc
CM
1528}
1529
1530static void get_sensor_evt_status(IPMIBmcSim *ibs,
1531 uint8_t *cmd, unsigned int cmd_len,
a580d820 1532 RspBuffer *rsp)
8bfffbcc
CM
1533{
1534 IPMISensor *sens;
1535
73d60fa5 1536 if ((cmd[2] >= MAX_SENSORS) ||
8bfffbcc 1537 !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
6acb971a 1538 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
d13ada5d 1539 return;
8bfffbcc
CM
1540 }
1541 sens = ibs->sensors + cmd[2];
a580d820
CLG
1542 rsp_buffer_push(rsp, sens->reading);
1543 rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1544 rsp_buffer_push(rsp, sens->assert_states & 0xff);
1545 rsp_buffer_push(rsp, (sens->assert_states >> 8) & 0xff);
1546 rsp_buffer_push(rsp, sens->deassert_states & 0xff);
1547 rsp_buffer_push(rsp, (sens->deassert_states >> 8) & 0xff);
8bfffbcc
CM
1548}
1549
1550static void get_sensor_reading(IPMIBmcSim *ibs,
1551 uint8_t *cmd, unsigned int cmd_len,
a580d820 1552 RspBuffer *rsp)
8bfffbcc
CM
1553{
1554 IPMISensor *sens;
1555
73d60fa5 1556 if ((cmd[2] >= MAX_SENSORS) ||
8bfffbcc 1557 !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
6acb971a 1558 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
d13ada5d 1559 return;
8bfffbcc
CM
1560 }
1561 sens = ibs->sensors + cmd[2];
a580d820
CLG
1562 rsp_buffer_push(rsp, sens->reading);
1563 rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1564 rsp_buffer_push(rsp, sens->states & 0xff);
8bfffbcc 1565 if (IPMI_SENSOR_IS_DISCRETE(sens)) {
a580d820 1566 rsp_buffer_push(rsp, (sens->states >> 8) & 0xff);
8bfffbcc 1567 }
8bfffbcc
CM
1568}
1569
728710e1 1570static void set_sensor_type(IPMIBmcSim *ibs,
a580d820
CLG
1571 uint8_t *cmd, unsigned int cmd_len,
1572 RspBuffer *rsp)
728710e1
CLG
1573{
1574 IPMISensor *sens;
1575
1576
73d60fa5 1577 if ((cmd[2] >= MAX_SENSORS) ||
728710e1 1578 !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
6acb971a 1579 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
728710e1
CLG
1580 return;
1581 }
1582 sens = ibs->sensors + cmd[2];
1583 sens->sensor_type = cmd[3];
1584 sens->evt_reading_type_code = cmd[4] & 0x7f;
1585}
1586
1587static void get_sensor_type(IPMIBmcSim *ibs,
a580d820
CLG
1588 uint8_t *cmd, unsigned int cmd_len,
1589 RspBuffer *rsp)
728710e1
CLG
1590{
1591 IPMISensor *sens;
1592
1593
73d60fa5 1594 if ((cmd[2] >= MAX_SENSORS) ||
728710e1 1595 !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
6acb971a 1596 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
728710e1
CLG
1597 return;
1598 }
1599 sens = ibs->sensors + cmd[2];
a580d820
CLG
1600 rsp_buffer_push(rsp, sens->sensor_type);
1601 rsp_buffer_push(rsp, sens->evt_reading_type_code);
728710e1
CLG
1602}
1603
1604
62a4931d 1605static const IPMICmdHandler chassis_cmds[] = {
4f298a4b
CLG
1606 [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = { chassis_capabilities },
1607 [IPMI_CMD_GET_CHASSIS_STATUS] = { chassis_status },
1608 [IPMI_CMD_CHASSIS_CONTROL] = { chassis_control, 3 },
1609 [IPMI_CMD_GET_SYS_RESTART_CAUSE] = { chassis_get_sys_restart_cause }
8bfffbcc
CM
1610};
1611static const IPMINetfn chassis_netfn = {
62a4931d 1612 .cmd_nums = ARRAY_SIZE(chassis_cmds),
8bfffbcc
CM
1613 .cmd_handlers = chassis_cmds
1614};
1615
62a4931d 1616static const IPMICmdHandler sensor_event_cmds[] = {
4f298a4b
CLG
1617 [IPMI_CMD_SET_SENSOR_EVT_ENABLE] = { set_sensor_evt_enable, 4 },
1618 [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = { get_sensor_evt_enable, 3 },
1619 [IPMI_CMD_REARM_SENSOR_EVTS] = { rearm_sensor_evts, 4 },
1620 [IPMI_CMD_GET_SENSOR_EVT_STATUS] = { get_sensor_evt_status, 3 },
1621 [IPMI_CMD_GET_SENSOR_READING] = { get_sensor_reading, 3 },
1622 [IPMI_CMD_SET_SENSOR_TYPE] = { set_sensor_type, 5 },
1623 [IPMI_CMD_GET_SENSOR_TYPE] = { get_sensor_type, 3 },
8bfffbcc
CM
1624};
1625static const IPMINetfn sensor_event_netfn = {
62a4931d 1626 .cmd_nums = ARRAY_SIZE(sensor_event_cmds),
8bfffbcc
CM
1627 .cmd_handlers = sensor_event_cmds
1628};
1629
62a4931d 1630static const IPMICmdHandler app_cmds[] = {
4f298a4b
CLG
1631 [IPMI_CMD_GET_DEVICE_ID] = { get_device_id },
1632 [IPMI_CMD_COLD_RESET] = { cold_reset },
1633 [IPMI_CMD_WARM_RESET] = { warm_reset },
1634 [IPMI_CMD_SET_ACPI_POWER_STATE] = { set_acpi_power_state, 4 },
1635 [IPMI_CMD_GET_ACPI_POWER_STATE] = { get_acpi_power_state },
1636 [IPMI_CMD_GET_DEVICE_GUID] = { get_device_guid },
1637 [IPMI_CMD_SET_BMC_GLOBAL_ENABLES] = { set_bmc_global_enables, 3 },
1638 [IPMI_CMD_GET_BMC_GLOBAL_ENABLES] = { get_bmc_global_enables },
1639 [IPMI_CMD_CLR_MSG_FLAGS] = { clr_msg_flags, 3 },
1640 [IPMI_CMD_GET_MSG_FLAGS] = { get_msg_flags },
1641 [IPMI_CMD_GET_MSG] = { get_msg },
1642 [IPMI_CMD_SEND_MSG] = { send_msg, 3 },
1643 [IPMI_CMD_READ_EVT_MSG_BUF] = { read_evt_msg_buf },
1644 [IPMI_CMD_RESET_WATCHDOG_TIMER] = { reset_watchdog_timer },
1645 [IPMI_CMD_SET_WATCHDOG_TIMER] = { set_watchdog_timer, 8 },
1646 [IPMI_CMD_GET_WATCHDOG_TIMER] = { get_watchdog_timer },
8bfffbcc
CM
1647};
1648static const IPMINetfn app_netfn = {
62a4931d 1649 .cmd_nums = ARRAY_SIZE(app_cmds),
8bfffbcc
CM
1650 .cmd_handlers = app_cmds
1651};
1652
62a4931d 1653static const IPMICmdHandler storage_cmds[] = {
4f298a4b
CLG
1654 [IPMI_CMD_GET_SDR_REP_INFO] = { get_sdr_rep_info },
1655 [IPMI_CMD_RESERVE_SDR_REP] = { reserve_sdr_rep },
1656 [IPMI_CMD_GET_SDR] = { get_sdr, 8 },
1657 [IPMI_CMD_ADD_SDR] = { add_sdr },
1658 [IPMI_CMD_CLEAR_SDR_REP] = { clear_sdr_rep, 8 },
1659 [IPMI_CMD_GET_SEL_INFO] = { get_sel_info },
1660 [IPMI_CMD_RESERVE_SEL] = { reserve_sel },
1661 [IPMI_CMD_GET_SEL_ENTRY] = { get_sel_entry, 8 },
1662 [IPMI_CMD_ADD_SEL_ENTRY] = { add_sel_entry, 18 },
1663 [IPMI_CMD_CLEAR_SEL] = { clear_sel, 8 },
1664 [IPMI_CMD_GET_SEL_TIME] = { get_sel_time, 6 },
1665 [IPMI_CMD_SET_SEL_TIME] = { set_sel_time },
8bfffbcc
CM
1666};
1667
1668static const IPMINetfn storage_netfn = {
62a4931d 1669 .cmd_nums = ARRAY_SIZE(storage_cmds),
8bfffbcc
CM
1670 .cmd_handlers = storage_cmds
1671};
1672
1673static void register_cmds(IPMIBmcSim *s)
1674{
1675 ipmi_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn);
1676 ipmi_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn);
1677 ipmi_register_netfn(s, IPMI_NETFN_APP, &app_netfn);
1678 ipmi_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn);
1679}
1680
5167560b 1681static uint8_t init_sdrs[] = {
8bfffbcc
CM
1682 /* Watchdog device */
1683 0x00, 0x00, 0x51, 0x02, 35, 0x20, 0x00, 0x00,
1684 0x23, 0x01, 0x63, 0x00, 0x23, 0x6f, 0x0f, 0x01,
1685 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1686 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8,
1687 'W', 'a', 't', 'c', 'h', 'd', 'o', 'g',
8bfffbcc
CM
1688};
1689
4fa9f08e
CLG
1690static void ipmi_sdr_init(IPMIBmcSim *ibs)
1691{
1692 unsigned int i;
52fc01d9 1693 int len;
5167560b
CLG
1694 size_t sdrs_size;
1695 uint8_t *sdrs;
4fa9f08e 1696
5167560b
CLG
1697 sdrs_size = sizeof(init_sdrs);
1698 sdrs = init_sdrs;
1699
1700 for (i = 0; i < sdrs_size; i += len) {
4fa9f08e 1701 struct ipmi_sdr_header *sdrh;
52fc01d9 1702
5167560b 1703 if (i + IPMI_SDR_HEADER_SIZE > sdrs_size) {
4fa9f08e
CLG
1704 error_report("Problem with recid 0x%4.4x", i);
1705 return;
1706 }
5167560b 1707 sdrh = (struct ipmi_sdr_header *) &sdrs[i];
4fa9f08e 1708 len = ipmi_sdr_length(sdrh);
5167560b 1709 if (i + len > sdrs_size) {
4fa9f08e
CLG
1710 error_report("Problem with recid 0x%4.4x", i);
1711 return;
1712 }
1713 sdr_add_entry(ibs, sdrh, len, NULL);
4fa9f08e
CLG
1714 }
1715}
1716
bd66bcfc
CM
1717static const VMStateDescription vmstate_ipmi_sim = {
1718 .name = TYPE_IPMI_BMC_SIMULATOR,
1719 .version_id = 1,
1720 .minimum_version_id = 1,
1721 .fields = (VMStateField[]) {
1722 VMSTATE_UINT8(bmc_global_enables, IPMIBmcSim),
1723 VMSTATE_UINT8(msg_flags, IPMIBmcSim),
1724 VMSTATE_BOOL(watchdog_initialized, IPMIBmcSim),
1725 VMSTATE_UINT8(watchdog_use, IPMIBmcSim),
1726 VMSTATE_UINT8(watchdog_action, IPMIBmcSim),
1727 VMSTATE_UINT8(watchdog_pretimeout, IPMIBmcSim),
1728 VMSTATE_BOOL(watchdog_expired, IPMIBmcSim),
1729 VMSTATE_UINT16(watchdog_timeout, IPMIBmcSim),
1730 VMSTATE_BOOL(watchdog_running, IPMIBmcSim),
1731 VMSTATE_BOOL(watchdog_preaction_ran, IPMIBmcSim),
1732 VMSTATE_INT64(watchdog_expiry, IPMIBmcSim),
1733 VMSTATE_UINT8_ARRAY(evtbuf, IPMIBmcSim, 16),
1734 VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].status, IPMIBmcSim),
1735 VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].reading, IPMIBmcSim),
1736 VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].states, IPMIBmcSim),
1737 VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_states, IPMIBmcSim),
1738 VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].deassert_states,
1739 IPMIBmcSim),
1740 VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_enable, IPMIBmcSim),
1741 VMSTATE_END_OF_LIST()
1742 }
1743};
1744
0bc6001f 1745static void ipmi_sim_realize(DeviceState *dev, Error **errp)
8bfffbcc 1746{
0bc6001f 1747 IPMIBmc *b = IPMI_BMC(dev);
8bfffbcc 1748 unsigned int i;
8bfffbcc
CM
1749 IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
1750
8bfffbcc
CM
1751 QTAILQ_INIT(&ibs->rcvbufs);
1752
1753 ibs->bmc_global_enables = (1 << IPMI_BMC_EVENT_LOG_BIT);
1754 ibs->device_id = 0x20;
1755 ibs->ipmi_version = 0x02; /* IPMI 2.0 */
b7088392 1756 ibs->restart_cause = 0;
8bfffbcc
CM
1757 for (i = 0; i < 4; i++) {
1758 ibs->sel.last_addition[i] = 0xff;
1759 ibs->sel.last_clear[i] = 0xff;
1760 ibs->sdr.last_addition[i] = 0xff;
1761 ibs->sdr.last_clear[i] = 0xff;
1762 }
1763
4fa9f08e 1764 ipmi_sdr_init(ibs);
8bfffbcc 1765
52ba4d50
CLG
1766 ibs->acpi_power_state[0] = 0;
1767 ibs->acpi_power_state[1] = 0;
1768
1769 if (qemu_uuid_set) {
9c5ce8db 1770 memcpy(&ibs->uuid, &qemu_uuid, 16);
52ba4d50
CLG
1771 } else {
1772 memset(&ibs->uuid, 0, 16);
1773 }
1774
8bfffbcc
CM
1775 ipmi_init_sensors_from_sdrs(ibs);
1776 register_cmds(ibs);
1777
1778 ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs);
bd66bcfc
CM
1779
1780 vmstate_register(NULL, 0, &vmstate_ipmi_sim, ibs);
8bfffbcc
CM
1781}
1782
1783static void ipmi_sim_class_init(ObjectClass *oc, void *data)
1784{
0bc6001f 1785 DeviceClass *dc = DEVICE_CLASS(oc);
8bfffbcc
CM
1786 IPMIBmcClass *bk = IPMI_BMC_CLASS(oc);
1787
66abfddb 1788 dc->hotpluggable = false;
0bc6001f 1789 dc->realize = ipmi_sim_realize;
8bfffbcc
CM
1790 bk->handle_command = ipmi_sim_handle_command;
1791}
1792
1793static const TypeInfo ipmi_sim_type = {
1794 .name = TYPE_IPMI_BMC_SIMULATOR,
1795 .parent = TYPE_IPMI_BMC,
1796 .instance_size = sizeof(IPMIBmcSim),
8bfffbcc
CM
1797 .class_init = ipmi_sim_class_init,
1798};
1799
1800static void ipmi_sim_register_types(void)
1801{
1802 type_register_static(&ipmi_sim_type);
1803}
1804
1805type_init(ipmi_sim_register_types)