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