]> Git Repo - qemu.git/blame - hw/ipmi/ipmi_bmc_sim.c
Merge remote-tracking branch 'remotes/ericb/tags/pull-bitmaps-2020-09-21' into staging
[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"
0b8fa32f 30#include "qemu/module.h"
8c6fd7f3 31#include "hw/loader.h"
a27bd6c7 32#include "hw/qdev-properties.h"
d6454270 33#include "migration/vmstate.h"
8bfffbcc
CM
34
35#define IPMI_NETFN_CHASSIS 0x00
8bfffbcc
CM
36
37#define IPMI_CMD_GET_CHASSIS_CAPABILITIES 0x00
38#define IPMI_CMD_GET_CHASSIS_STATUS 0x01
39#define IPMI_CMD_CHASSIS_CONTROL 0x02
b7088392 40#define IPMI_CMD_GET_SYS_RESTART_CAUSE 0x09
8bfffbcc
CM
41
42#define IPMI_NETFN_SENSOR_EVENT 0x04
8bfffbcc 43
9380d2ed 44#define IPMI_CMD_PLATFORM_EVENT_MSG 0x02
8bfffbcc
CM
45#define IPMI_CMD_SET_SENSOR_EVT_ENABLE 0x28
46#define IPMI_CMD_GET_SENSOR_EVT_ENABLE 0x29
47#define IPMI_CMD_REARM_SENSOR_EVTS 0x2a
48#define IPMI_CMD_GET_SENSOR_EVT_STATUS 0x2b
49#define IPMI_CMD_GET_SENSOR_READING 0x2d
728710e1
CLG
50#define IPMI_CMD_SET_SENSOR_TYPE 0x2e
51#define IPMI_CMD_GET_SENSOR_TYPE 0x2f
e3f7320c 52#define IPMI_CMD_SET_SENSOR_READING 0x30
8bfffbcc
CM
53
54/* #define IPMI_NETFN_APP 0x06 In ipmi.h */
8bfffbcc
CM
55
56#define IPMI_CMD_GET_DEVICE_ID 0x01
57#define IPMI_CMD_COLD_RESET 0x02
58#define IPMI_CMD_WARM_RESET 0x03
52ba4d50
CLG
59#define IPMI_CMD_SET_ACPI_POWER_STATE 0x06
60#define IPMI_CMD_GET_ACPI_POWER_STATE 0x07
61#define IPMI_CMD_GET_DEVICE_GUID 0x08
8bfffbcc
CM
62#define IPMI_CMD_RESET_WATCHDOG_TIMER 0x22
63#define IPMI_CMD_SET_WATCHDOG_TIMER 0x24
64#define IPMI_CMD_GET_WATCHDOG_TIMER 0x25
65#define IPMI_CMD_SET_BMC_GLOBAL_ENABLES 0x2e
66#define IPMI_CMD_GET_BMC_GLOBAL_ENABLES 0x2f
67#define IPMI_CMD_CLR_MSG_FLAGS 0x30
68#define IPMI_CMD_GET_MSG_FLAGS 0x31
69#define IPMI_CMD_GET_MSG 0x33
70#define IPMI_CMD_SEND_MSG 0x34
71#define IPMI_CMD_READ_EVT_MSG_BUF 0x35
72
73#define IPMI_NETFN_STORAGE 0x0a
8bfffbcc
CM
74
75#define IPMI_CMD_GET_SDR_REP_INFO 0x20
76#define IPMI_CMD_GET_SDR_REP_ALLOC_INFO 0x21
77#define IPMI_CMD_RESERVE_SDR_REP 0x22
78#define IPMI_CMD_GET_SDR 0x23
79#define IPMI_CMD_ADD_SDR 0x24
80#define IPMI_CMD_PARTIAL_ADD_SDR 0x25
81#define IPMI_CMD_DELETE_SDR 0x26
82#define IPMI_CMD_CLEAR_SDR_REP 0x27
83#define IPMI_CMD_GET_SDR_REP_TIME 0x28
84#define IPMI_CMD_SET_SDR_REP_TIME 0x29
85#define IPMI_CMD_ENTER_SDR_REP_UPD_MODE 0x2A
86#define IPMI_CMD_EXIT_SDR_REP_UPD_MODE 0x2B
87#define IPMI_CMD_RUN_INIT_AGENT 0x2C
540c07d3
CLG
88#define IPMI_CMD_GET_FRU_AREA_INFO 0x10
89#define IPMI_CMD_READ_FRU_DATA 0x11
90#define IPMI_CMD_WRITE_FRU_DATA 0x12
8bfffbcc
CM
91#define IPMI_CMD_GET_SEL_INFO 0x40
92#define IPMI_CMD_GET_SEL_ALLOC_INFO 0x41
93#define IPMI_CMD_RESERVE_SEL 0x42
94#define IPMI_CMD_GET_SEL_ENTRY 0x43
95#define IPMI_CMD_ADD_SEL_ENTRY 0x44
96#define IPMI_CMD_PARTIAL_ADD_SEL_ENTRY 0x45
97#define IPMI_CMD_DELETE_SEL_ENTRY 0x46
98#define IPMI_CMD_CLEAR_SEL 0x47
99#define IPMI_CMD_GET_SEL_TIME 0x48
100#define IPMI_CMD_SET_SEL_TIME 0x49
101
102
103/* Same as a timespec struct. */
104struct ipmi_time {
105 long tv_sec;
106 long tv_nsec;
107};
108
109#define MAX_SEL_SIZE 128
110
111typedef struct IPMISel {
112 uint8_t sel[MAX_SEL_SIZE][16];
113 unsigned int next_free;
114 long time_offset;
115 uint16_t reservation;
116 uint8_t last_addition[4];
117 uint8_t last_clear[4];
118 uint8_t overflow;
119} IPMISel;
120
121#define MAX_SDR_SIZE 16384
122
123typedef struct IPMISdr {
124 uint8_t sdr[MAX_SDR_SIZE];
125 unsigned int next_free;
126 uint16_t next_rec_id;
127 uint16_t reservation;
128 uint8_t last_addition[4];
129 uint8_t last_clear[4];
130 uint8_t overflow;
131} IPMISdr;
132
540c07d3
CLG
133typedef struct IPMIFru {
134 char *filename;
135 unsigned int nentries;
136 uint16_t areasize;
137 uint8_t *data;
138} IPMIFru;
139
8bfffbcc
CM
140typedef struct IPMISensor {
141 uint8_t status;
142 uint8_t reading;
143 uint16_t states_suppt;
144 uint16_t assert_suppt;
145 uint16_t deassert_suppt;
146 uint16_t states;
147 uint16_t assert_states;
148 uint16_t deassert_states;
149 uint16_t assert_enable;
150 uint16_t deassert_enable;
151 uint8_t sensor_type;
152 uint8_t evt_reading_type_code;
153} IPMISensor;
154#define IPMI_SENSOR_GET_PRESENT(s) ((s)->status & 0x01)
155#define IPMI_SENSOR_SET_PRESENT(s, v) ((s)->status = (s->status & ~0x01) | \
156 !!(v))
157#define IPMI_SENSOR_GET_SCAN_ON(s) ((s)->status & 0x40)
158#define IPMI_SENSOR_SET_SCAN_ON(s, v) ((s)->status = (s->status & ~0x40) | \
159 ((!!(v)) << 6))
160#define IPMI_SENSOR_GET_EVENTS_ON(s) ((s)->status & 0x80)
161#define IPMI_SENSOR_SET_EVENTS_ON(s, v) ((s)->status = (s->status & ~0x80) | \
162 ((!!(v)) << 7))
163#define IPMI_SENSOR_GET_RET_STATUS(s) ((s)->status & 0xc0)
164#define IPMI_SENSOR_SET_RET_STATUS(s, v) ((s)->status = (s->status & ~0xc0) | \
165 (v & 0xc0))
166#define IPMI_SENSOR_IS_DISCRETE(s) ((s)->evt_reading_type_code != 1)
167
168#define MAX_SENSORS 20
169#define IPMI_WATCHDOG_SENSOR 0
170
8bfffbcc 171#define MAX_NETFNS 64
4f298a4b 172
8bfffbcc
CM
173typedef struct IPMIRcvBufEntry {
174 QTAILQ_ENTRY(IPMIRcvBufEntry) entry;
175 uint8_t len;
176 uint8_t buf[MAX_IPMI_MSG_SIZE];
177} IPMIRcvBufEntry;
178
8bfffbcc
CM
179struct IPMIBmcSim {
180 IPMIBmc parent;
181
182 QEMUTimer *timer;
183
184 uint8_t bmc_global_enables;
185 uint8_t msg_flags;
186
187 bool watchdog_initialized;
188 uint8_t watchdog_use;
189 uint8_t watchdog_action;
190 uint8_t watchdog_pretimeout; /* In seconds */
191 bool watchdog_expired;
192 uint16_t watchdog_timeout; /* in 100's of milliseconds */
193
194 bool watchdog_running;
195 bool watchdog_preaction_ran;
196 int64_t watchdog_expiry;
197
198 uint8_t device_id;
199 uint8_t ipmi_version;
200 uint8_t device_rev;
201 uint8_t fwrev1;
202 uint8_t fwrev2;
20b23364
CM
203 uint32_t mfg_id;
204 uint16_t product_id;
8bfffbcc 205
b7088392
CLG
206 uint8_t restart_cause;
207
52ba4d50 208 uint8_t acpi_power_state[2];
7b0cd78b 209 QemuUUID uuid;
52ba4d50 210
8bfffbcc
CM
211 IPMISel sel;
212 IPMISdr sdr;
540c07d3 213 IPMIFru fru;
8bfffbcc 214 IPMISensor sensors[MAX_SENSORS];
8c6fd7f3 215 char *sdr_filename;
8bfffbcc
CM
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 265#define RSP_BUFFER_INITIALIZER { }
8bfffbcc 266
a580d820
CLG
267static inline void rsp_buffer_pushmore(RspBuffer *rsp, uint8_t *bytes,
268 unsigned int n)
269{
270 if (rsp->len + n >= sizeof(rsp->buffer)) {
6acb971a 271 rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
a580d820
CLG
272 return;
273 }
274
275 memcpy(&rsp->buffer[rsp->len], bytes, n);
276 rsp->len += n;
277}
8bfffbcc 278
8bfffbcc
CM
279static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs);
280
281static void ipmi_gettime(struct ipmi_time *time)
282{
283 int64_t stime;
284
285 stime = qemu_clock_get_ns(QEMU_CLOCK_HOST);
286 time->tv_sec = stime / 1000000000LL;
287 time->tv_nsec = stime % 1000000000LL;
288}
289
290static int64_t ipmi_getmonotime(void)
291{
292 return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
293}
294
295static void ipmi_timeout(void *opaque)
296{
297 IPMIBmcSim *ibs = opaque;
298
299 ipmi_sim_handle_timeout(ibs);
300}
301
302static void set_timestamp(IPMIBmcSim *ibs, uint8_t *ts)
303{
304 unsigned int val;
305 struct ipmi_time now;
306
307 ipmi_gettime(&now);
308 val = now.tv_sec + ibs->sel.time_offset;
309 ts[0] = val & 0xff;
310 ts[1] = (val >> 8) & 0xff;
311 ts[2] = (val >> 16) & 0xff;
312 ts[3] = (val >> 24) & 0xff;
313}
314
315static void sdr_inc_reservation(IPMISdr *sdr)
316{
317 sdr->reservation++;
318 if (sdr->reservation == 0) {
319 sdr->reservation = 1;
320 }
321}
322
a2295f0a
CLG
323static int sdr_add_entry(IPMIBmcSim *ibs,
324 const struct ipmi_sdr_header *sdrh_entry,
8bfffbcc
CM
325 unsigned int len, uint16_t *recid)
326{
a2295f0a
CLG
327 struct ipmi_sdr_header *sdrh =
328 (struct ipmi_sdr_header *) &ibs->sdr.sdr[ibs->sdr.next_free];
329
330 if ((len < IPMI_SDR_HEADER_SIZE) || (len > 255)) {
8bfffbcc
CM
331 return 1;
332 }
333
a2295f0a 334 if (ipmi_sdr_length(sdrh_entry) != len) {
8bfffbcc
CM
335 return 1;
336 }
337
338 if (ibs->sdr.next_free + len > MAX_SDR_SIZE) {
339 ibs->sdr.overflow = 1;
340 return 1;
341 }
342
a2295f0a
CLG
343 memcpy(sdrh, sdrh_entry, len);
344 sdrh->rec_id[0] = ibs->sdr.next_rec_id & 0xff;
345 sdrh->rec_id[1] = (ibs->sdr.next_rec_id >> 8) & 0xff;
346 sdrh->sdr_version = 0x51; /* Conform to IPMI 1.5 spec */
8bfffbcc
CM
347
348 if (recid) {
349 *recid = ibs->sdr.next_rec_id;
350 }
351 ibs->sdr.next_rec_id++;
352 set_timestamp(ibs, ibs->sdr.last_addition);
353 ibs->sdr.next_free += len;
354 sdr_inc_reservation(&ibs->sdr);
355 return 0;
356}
357
358static int sdr_find_entry(IPMISdr *sdr, uint16_t recid,
359 unsigned int *retpos, uint16_t *nextrec)
360{
361 unsigned int pos = *retpos;
362
363 while (pos < sdr->next_free) {
a2295f0a
CLG
364 struct ipmi_sdr_header *sdrh =
365 (struct ipmi_sdr_header *) &sdr->sdr[pos];
366 uint16_t trec = ipmi_sdr_recid(sdrh);
367 unsigned int nextpos = pos + ipmi_sdr_length(sdrh);
8bfffbcc
CM
368
369 if (trec == recid) {
370 if (nextrec) {
371 if (nextpos >= sdr->next_free) {
372 *nextrec = 0xffff;
373 } else {
374 *nextrec = (sdr->sdr[nextpos] |
375 (sdr->sdr[nextpos + 1] << 8));
376 }
377 }
378 *retpos = pos;
379 return 0;
380 }
381 pos = nextpos;
382 }
383 return 1;
384}
385
7fabcdb9
CLG
386int ipmi_bmc_sdr_find(IPMIBmc *b, uint16_t recid,
387 const struct ipmi_sdr_compact **sdr, uint16_t *nextrec)
388
389{
390 IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
391 unsigned int pos;
392
393 pos = 0;
394 if (sdr_find_entry(&ibs->sdr, recid, &pos, nextrec)) {
395 return -1;
396 }
397
398 *sdr = (const struct ipmi_sdr_compact *) &ibs->sdr.sdr[pos];
399 return 0;
400}
401
8bfffbcc
CM
402static void sel_inc_reservation(IPMISel *sel)
403{
404 sel->reservation++;
405 if (sel->reservation == 0) {
406 sel->reservation = 1;
407 }
408}
409
410/* Returns 1 if the SEL is full and can't hold the event. */
411static int sel_add_event(IPMIBmcSim *ibs, uint8_t *event)
412{
9f7d1d92
CM
413 uint8_t ts[4];
414
8bfffbcc
CM
415 event[0] = 0xff;
416 event[1] = 0xff;
9f7d1d92
CM
417 set_timestamp(ibs, ts);
418 if (event[2] < 0xe0) { /* Don't set timestamps for type 0xe0-0xff. */
419 memcpy(event + 3, ts, 4);
420 }
8bfffbcc
CM
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;
9f7d1d92 427 memcpy(ibs->sel.last_addition, ts, 4);
8bfffbcc
CM
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{
8bc8af69
CM
443 return (IPMI_BMC_MSG_INTS_ON(ibs) &&
444 (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs) ||
445 IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs)))
8bfffbcc
CM
446 || (IPMI_BMC_EVBUF_FULL_INT_ENABLED(ibs) &&
447 IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs));
448}
449
cd60d85e
CLG
450void ipmi_bmc_gen_event(IPMIBmc *b, uint8_t *evt, bool log)
451{
452 IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
453 IPMIInterface *s = ibs->parent.intf;
454 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
455
456 if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) {
457 return;
458 }
459
460 if (log && IPMI_BMC_EVENT_LOG_ENABLED(ibs)) {
461 sel_add_event(ibs, evt);
462 }
463
464 if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) {
465 goto out;
466 }
467
468 memcpy(ibs->evtbuf, evt, 16);
469 ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
470 k->set_atn(s, 1, attn_irq_enabled(ibs));
471 out:
472 return;
473}
8bfffbcc
CM
474static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert,
475 uint8_t evd1, uint8_t evd2, uint8_t evd3)
476{
477 IPMIInterface *s = ibs->parent.intf;
478 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
479 uint8_t evt[16];
480 IPMISensor *sens = ibs->sensors + sens_num;
481
482 if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) {
483 return;
484 }
485 if (!IPMI_SENSOR_GET_EVENTS_ON(sens)) {
486 return;
487 }
488
489 evt[2] = 0x2; /* System event record */
490 evt[7] = ibs->parent.slave_addr;
491 evt[8] = 0;
492 evt[9] = 0x04; /* Format version */
493 evt[10] = sens->sensor_type;
494 evt[11] = sens_num;
495 evt[12] = sens->evt_reading_type_code | (!!deassert << 7);
496 evt[13] = evd1;
497 evt[14] = evd2;
498 evt[15] = evd3;
499
500 if (IPMI_BMC_EVENT_LOG_ENABLED(ibs)) {
501 sel_add_event(ibs, evt);
502 }
503
504 if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) {
d13ada5d 505 return;
8bfffbcc
CM
506 }
507
508 memcpy(ibs->evtbuf, evt, 16);
509 ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
510 k->set_atn(s, 1, attn_irq_enabled(ibs));
8bfffbcc
CM
511}
512
513static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor,
514 unsigned int bit, unsigned int val,
515 uint8_t evd1, uint8_t evd2, uint8_t evd3)
516{
517 IPMISensor *sens;
518 uint16_t mask;
519
520 if (sensor >= MAX_SENSORS) {
521 return;
522 }
523 if (bit >= 16) {
524 return;
525 }
526
527 mask = (1 << bit);
528 sens = ibs->sensors + sensor;
529 if (val) {
530 sens->states |= mask & sens->states_suppt;
531 if (sens->assert_states & mask) {
532 return; /* Already asserted */
533 }
534 sens->assert_states |= mask & sens->assert_suppt;
535 if (sens->assert_enable & mask & sens->assert_states) {
536 /* Send an event on assert */
537 gen_event(ibs, sensor, 0, evd1, evd2, evd3);
538 }
539 } else {
540 sens->states &= ~(mask & sens->states_suppt);
541 if (sens->deassert_states & mask) {
542 return; /* Already deasserted */
543 }
544 sens->deassert_states |= mask & sens->deassert_suppt;
545 if (sens->deassert_enable & mask & sens->deassert_states) {
546 /* Send an event on deassert */
547 gen_event(ibs, sensor, 1, evd1, evd2, evd3);
548 }
549 }
550}
551
552static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s)
553{
554 unsigned int i, pos;
555 IPMISensor *sens;
556
557 for (i = 0; i < MAX_SENSORS; i++) {
558 memset(s->sensors + i, 0, sizeof(*sens));
559 }
560
561 pos = 0;
562 for (i = 0; !sdr_find_entry(&s->sdr, i, &pos, NULL); i++) {
a2295f0a
CLG
563 struct ipmi_sdr_compact *sdr =
564 (struct ipmi_sdr_compact *) &s->sdr.sdr[pos];
565 unsigned int len = sdr->header.rec_length;
8bfffbcc
CM
566
567 if (len < 20) {
568 continue;
569 }
a2295f0a 570 if (sdr->header.rec_type != IPMI_SDR_COMPACT_TYPE) {
8bfffbcc
CM
571 continue; /* Not a sensor SDR we set from */
572 }
573
73d60fa5 574 if (sdr->sensor_owner_number >= MAX_SENSORS) {
8bfffbcc
CM
575 continue;
576 }
a2295f0a 577 sens = s->sensors + sdr->sensor_owner_number;
8bfffbcc
CM
578
579 IPMI_SENSOR_SET_PRESENT(sens, 1);
a2295f0a
CLG
580 IPMI_SENSOR_SET_SCAN_ON(sens, (sdr->sensor_init >> 6) & 1);
581 IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr->sensor_init >> 5) & 1);
582 sens->assert_suppt = sdr->assert_mask[0] | (sdr->assert_mask[1] << 8);
583 sens->deassert_suppt =
584 sdr->deassert_mask[0] | (sdr->deassert_mask[1] << 8);
585 sens->states_suppt =
586 sdr->discrete_mask[0] | (sdr->discrete_mask[1] << 8);
587 sens->sensor_type = sdr->sensor_type;
588 sens->evt_reading_type_code = sdr->reading_type & 0x7f;
8bfffbcc
CM
589
590 /* Enable all the events that are supported. */
591 sens->assert_enable = sens->assert_suppt;
592 sens->deassert_enable = sens->deassert_suppt;
593 }
594}
595
ed8da05c
CLG
596int ipmi_sim_register_netfn(IPMIBmcSim *s, unsigned int netfn,
597 const IPMINetfn *netfnd)
8bfffbcc 598{
93a53646 599 if ((netfn & 1) || (netfn >= MAX_NETFNS) || (s->netfns[netfn / 2])) {
8bfffbcc
CM
600 return -1;
601 }
602 s->netfns[netfn / 2] = netfnd;
603 return 0;
604}
605
4f298a4b
CLG
606static const IPMICmdHandler *ipmi_get_handler(IPMIBmcSim *ibs,
607 unsigned int netfn,
608 unsigned int cmd)
609{
610 const IPMICmdHandler *hdl;
611
612 if (netfn & 1 || netfn >= MAX_NETFNS || !ibs->netfns[netfn / 2]) {
613 return NULL;
614 }
615
616 if (cmd >= ibs->netfns[netfn / 2]->cmd_nums) {
617 return NULL;
618 }
619
620 hdl = &ibs->netfns[netfn / 2]->cmd_handlers[cmd];
621 if (!hdl->cmd_handler) {
622 return NULL;
623 }
624
625 return hdl;
626}
627
8bfffbcc
CM
628static void next_timeout(IPMIBmcSim *ibs)
629{
630 int64_t next;
631 if (ibs->watchdog_running) {
632 next = ibs->watchdog_expiry;
633 } else {
634 /* Wait a minute */
635 next = ipmi_getmonotime() + 60 * 1000000000LL;
636 }
637 timer_mod_ns(ibs->timer, next);
638}
639
640static void ipmi_sim_handle_command(IPMIBmc *b,
641 uint8_t *cmd, unsigned int cmd_len,
642 unsigned int max_cmd_len,
643 uint8_t msg_id)
644{
645 IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
646 IPMIInterface *s = ibs->parent.intf;
647 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
4f298a4b 648 const IPMICmdHandler *hdl;
a580d820 649 RspBuffer rsp = RSP_BUFFER_INITIALIZER;
8bfffbcc
CM
650
651 /* Set up the response, set the low bit of NETFN. */
652 /* Note that max_rsp_len must be at least 3 */
a580d820 653 if (sizeof(rsp.buffer) < 3) {
6acb971a 654 rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
d13ada5d
CLG
655 goto out;
656 }
657
a580d820
CLG
658 rsp_buffer_push(&rsp, cmd[0] | 0x04);
659 rsp_buffer_push(&rsp, cmd[1]);
660 rsp_buffer_push(&rsp, 0); /* Assume success */
8bfffbcc
CM
661
662 /* If it's too short or it was truncated, return an error. */
663 if (cmd_len < 2) {
6acb971a 664 rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
8bfffbcc
CM
665 goto out;
666 }
667 if (cmd_len > max_cmd_len) {
6acb971a 668 rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
8bfffbcc
CM
669 goto out;
670 }
671
672 if ((cmd[0] & 0x03) != 0) {
673 /* Only have stuff on LUN 0 */
6acb971a 674 rsp_buffer_set_error(&rsp, IPMI_CC_COMMAND_INVALID_FOR_LUN);
8bfffbcc
CM
675 goto out;
676 }
677
4f298a4b
CLG
678 hdl = ipmi_get_handler(ibs, cmd[0] >> 2, cmd[1]);
679 if (!hdl) {
6acb971a 680 rsp_buffer_set_error(&rsp, IPMI_CC_INVALID_CMD);
8bfffbcc
CM
681 goto out;
682 }
683
4f298a4b 684 if (cmd_len < hdl->cmd_len_min) {
6acb971a 685 rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
4f298a4b
CLG
686 goto out;
687 }
688
a580d820 689 hdl->cmd_handler(ibs, cmd, cmd_len, &rsp);
8bfffbcc
CM
690
691 out:
a580d820 692 k->handle_rsp(s, msg_id, rsp.buffer, rsp.len);
8bfffbcc
CM
693
694 next_timeout(ibs);
695}
696
697static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs)
698{
699 IPMIInterface *s = ibs->parent.intf;
700 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
701
702 if (!ibs->watchdog_running) {
703 goto out;
704 }
705
706 if (!ibs->watchdog_preaction_ran) {
707 switch (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs)) {
708 case IPMI_BMC_WATCHDOG_PRE_NMI:
709 ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
710 k->do_hw_op(s, IPMI_SEND_NMI, 0);
711 sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
712 0xc8, (2 << 4) | 0xf, 0xff);
713 break;
714
715 case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
716 ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
717 k->set_atn(s, 1, attn_irq_enabled(ibs));
718 sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
719 0xc8, (3 << 4) | 0xf, 0xff);
720 break;
721
722 default:
723 goto do_full_expiry;
724 }
725
726 ibs->watchdog_preaction_ran = 1;
727 /* Issued the pretimeout, do the rest of the timeout now. */
728 ibs->watchdog_expiry = ipmi_getmonotime();
729 ibs->watchdog_expiry += ibs->watchdog_pretimeout * 1000000000LL;
730 goto out;
731 }
732
733 do_full_expiry:
734 ibs->watchdog_running = 0; /* Stop the watchdog on a timeout */
735 ibs->watchdog_expired |= (1 << IPMI_BMC_WATCHDOG_GET_USE(ibs));
736 switch (IPMI_BMC_WATCHDOG_GET_ACTION(ibs)) {
737 case IPMI_BMC_WATCHDOG_ACTION_NONE:
738 sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 0, 1,
739 0xc0, ibs->watchdog_use & 0xf, 0xff);
740 break;
741
742 case IPMI_BMC_WATCHDOG_ACTION_RESET:
743 sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 1, 1,
744 0xc1, ibs->watchdog_use & 0xf, 0xff);
745 k->do_hw_op(s, IPMI_RESET_CHASSIS, 0);
746 break;
747
748 case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
749 sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
750 0xc2, ibs->watchdog_use & 0xf, 0xff);
751 k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0);
752 break;
753
754 case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
755 sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
756 0xc3, ibs->watchdog_use & 0xf, 0xff);
757 k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0);
758 break;
759 }
760
761 out:
762 next_timeout(ibs);
763}
764
765static void chassis_capabilities(IPMIBmcSim *ibs,
766 uint8_t *cmd, unsigned int cmd_len,
a580d820 767 RspBuffer *rsp)
8bfffbcc 768{
a580d820
CLG
769 rsp_buffer_push(rsp, 0);
770 rsp_buffer_push(rsp, ibs->parent.slave_addr);
771 rsp_buffer_push(rsp, ibs->parent.slave_addr);
772 rsp_buffer_push(rsp, ibs->parent.slave_addr);
773 rsp_buffer_push(rsp, ibs->parent.slave_addr);
8bfffbcc
CM
774}
775
776static void chassis_status(IPMIBmcSim *ibs,
777 uint8_t *cmd, unsigned int cmd_len,
a580d820 778 RspBuffer *rsp)
8bfffbcc 779{
a580d820
CLG
780 rsp_buffer_push(rsp, 0x61); /* Unknown power restore, power is on */
781 rsp_buffer_push(rsp, 0);
782 rsp_buffer_push(rsp, 0);
783 rsp_buffer_push(rsp, 0);
8bfffbcc
CM
784}
785
786static void chassis_control(IPMIBmcSim *ibs,
787 uint8_t *cmd, unsigned int cmd_len,
a580d820 788 RspBuffer *rsp)
8bfffbcc
CM
789{
790 IPMIInterface *s = ibs->parent.intf;
791 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
792
8bfffbcc
CM
793 switch (cmd[2] & 0xf) {
794 case 0: /* power down */
6acb971a 795 rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0));
8bfffbcc
CM
796 break;
797 case 1: /* power up */
6acb971a 798 rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERON_CHASSIS, 0));
8bfffbcc
CM
799 break;
800 case 2: /* power cycle */
6acb971a 801 rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0));
8bfffbcc
CM
802 break;
803 case 3: /* hard reset */
6acb971a 804 rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 0));
8bfffbcc
CM
805 break;
806 case 4: /* pulse diagnostic interrupt */
6acb971a 807 rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_PULSE_DIAG_IRQ, 0));
8bfffbcc
CM
808 break;
809 case 5: /* soft shutdown via ACPI by overtemp emulation */
6acb971a
CLG
810 rsp_buffer_set_error(rsp, k->do_hw_op(s,
811 IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 0));
8bfffbcc
CM
812 break;
813 default:
6acb971a 814 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
d13ada5d 815 return;
8bfffbcc 816 }
8bfffbcc
CM
817}
818
b7088392
CLG
819static void chassis_get_sys_restart_cause(IPMIBmcSim *ibs,
820 uint8_t *cmd, unsigned int cmd_len,
a580d820
CLG
821 RspBuffer *rsp)
822
b7088392 823{
a580d820
CLG
824 rsp_buffer_push(rsp, ibs->restart_cause & 0xf); /* Restart Cause */
825 rsp_buffer_push(rsp, 0); /* Channel 0 */
b7088392
CLG
826}
827
8bfffbcc
CM
828static void get_device_id(IPMIBmcSim *ibs,
829 uint8_t *cmd, unsigned int cmd_len,
a580d820 830 RspBuffer *rsp)
8bfffbcc 831{
a580d820
CLG
832 rsp_buffer_push(rsp, ibs->device_id);
833 rsp_buffer_push(rsp, ibs->device_rev & 0xf);
834 rsp_buffer_push(rsp, ibs->fwrev1 & 0x7f);
835 rsp_buffer_push(rsp, ibs->fwrev2);
836 rsp_buffer_push(rsp, ibs->ipmi_version);
837 rsp_buffer_push(rsp, 0x07); /* sensor, SDR, and SEL. */
20b23364
CM
838 rsp_buffer_push(rsp, ibs->mfg_id & 0xff);
839 rsp_buffer_push(rsp, (ibs->mfg_id >> 8) & 0xff);
840 rsp_buffer_push(rsp, (ibs->mfg_id >> 16) & 0xff);
841 rsp_buffer_push(rsp, ibs->product_id & 0xff);
842 rsp_buffer_push(rsp, (ibs->product_id >> 8) & 0xff);
8bfffbcc
CM
843}
844
845static void set_global_enables(IPMIBmcSim *ibs, uint8_t val)
846{
847 IPMIInterface *s = ibs->parent.intf;
848 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
849 bool irqs_on;
850
851 ibs->bmc_global_enables = val;
852
853 irqs_on = val & (IPMI_BMC_EVBUF_FULL_INT_BIT |
854 IPMI_BMC_RCV_MSG_QUEUE_INT_BIT);
855
856 k->set_irq_enable(s, irqs_on);
857}
858
859static void cold_reset(IPMIBmcSim *ibs,
860 uint8_t *cmd, unsigned int cmd_len,
a580d820 861 RspBuffer *rsp)
8bfffbcc
CM
862{
863 IPMIInterface *s = ibs->parent.intf;
864 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
865
866 /* Disable all interrupts */
867 set_global_enables(ibs, 1 << IPMI_BMC_EVENT_LOG_BIT);
868
869 if (k->reset) {
870 k->reset(s, true);
871 }
872}
873
874static void warm_reset(IPMIBmcSim *ibs,
875 uint8_t *cmd, unsigned int cmd_len,
a580d820 876 RspBuffer *rsp)
8bfffbcc
CM
877{
878 IPMIInterface *s = ibs->parent.intf;
879 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
880
881 if (k->reset) {
882 k->reset(s, false);
883 }
884}
52ba4d50 885static void set_acpi_power_state(IPMIBmcSim *ibs,
a580d820
CLG
886 uint8_t *cmd, unsigned int cmd_len,
887 RspBuffer *rsp)
52ba4d50 888{
52ba4d50
CLG
889 ibs->acpi_power_state[0] = cmd[2];
890 ibs->acpi_power_state[1] = cmd[3];
891}
892
893static void get_acpi_power_state(IPMIBmcSim *ibs,
a580d820
CLG
894 uint8_t *cmd, unsigned int cmd_len,
895 RspBuffer *rsp)
52ba4d50 896{
a580d820
CLG
897 rsp_buffer_push(rsp, ibs->acpi_power_state[0]);
898 rsp_buffer_push(rsp, ibs->acpi_power_state[1]);
52ba4d50
CLG
899}
900
901static void get_device_guid(IPMIBmcSim *ibs,
a580d820
CLG
902 uint8_t *cmd, unsigned int cmd_len,
903 RspBuffer *rsp)
52ba4d50
CLG
904{
905 unsigned int i;
906
7b0cd78b 907 /* An uninitialized uuid is all zeros, use that to know if it is set. */
52ba4d50 908 for (i = 0; i < 16; i++) {
7b0cd78b
CM
909 if (ibs->uuid.data[i]) {
910 goto uuid_set;
911 }
912 }
913 /* No uuid is set, return an error. */
914 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_CMD);
915 return;
916
917 uuid_set:
918 for (i = 0; i < 16; i++) {
919 rsp_buffer_push(rsp, ibs->uuid.data[i]);
52ba4d50
CLG
920 }
921}
8bfffbcc
CM
922
923static void set_bmc_global_enables(IPMIBmcSim *ibs,
924 uint8_t *cmd, unsigned int cmd_len,
a580d820 925 RspBuffer *rsp)
8bfffbcc 926{
8bfffbcc 927 set_global_enables(ibs, cmd[2]);
8bfffbcc
CM
928}
929
930static void get_bmc_global_enables(IPMIBmcSim *ibs,
931 uint8_t *cmd, unsigned int cmd_len,
a580d820 932 RspBuffer *rsp)
8bfffbcc 933{
a580d820 934 rsp_buffer_push(rsp, ibs->bmc_global_enables);
8bfffbcc
CM
935}
936
937static void clr_msg_flags(IPMIBmcSim *ibs,
938 uint8_t *cmd, unsigned int cmd_len,
a580d820 939 RspBuffer *rsp)
8bfffbcc
CM
940{
941 IPMIInterface *s = ibs->parent.intf;
942 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
943
8bfffbcc
CM
944 ibs->msg_flags &= ~cmd[2];
945 k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
8bfffbcc
CM
946}
947
948static void get_msg_flags(IPMIBmcSim *ibs,
949 uint8_t *cmd, unsigned int cmd_len,
a580d820 950 RspBuffer *rsp)
8bfffbcc 951{
a580d820 952 rsp_buffer_push(rsp, ibs->msg_flags);
8bfffbcc
CM
953}
954
955static void read_evt_msg_buf(IPMIBmcSim *ibs,
956 uint8_t *cmd, unsigned int cmd_len,
a580d820 957 RspBuffer *rsp)
8bfffbcc
CM
958{
959 IPMIInterface *s = ibs->parent.intf;
960 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
961 unsigned int i;
962
963 if (!(ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL)) {
6acb971a 964 rsp_buffer_set_error(rsp, 0x80);
d13ada5d 965 return;
8bfffbcc
CM
966 }
967 for (i = 0; i < 16; i++) {
a580d820 968 rsp_buffer_push(rsp, ibs->evtbuf[i]);
8bfffbcc
CM
969 }
970 ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
971 k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
8bfffbcc
CM
972}
973
974static void get_msg(IPMIBmcSim *ibs,
975 uint8_t *cmd, unsigned int cmd_len,
a580d820 976 RspBuffer *rsp)
8bfffbcc
CM
977{
978 IPMIRcvBufEntry *msg;
979
8bfffbcc 980 if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
6acb971a 981 rsp_buffer_set_error(rsp, 0x80); /* Queue empty */
8bfffbcc
CM
982 goto out;
983 }
a580d820 984 rsp_buffer_push(rsp, 0); /* Channel 0 */
8bfffbcc 985 msg = QTAILQ_FIRST(&ibs->rcvbufs);
a580d820 986 rsp_buffer_pushmore(rsp, msg->buf, msg->len);
8bfffbcc
CM
987 QTAILQ_REMOVE(&ibs->rcvbufs, msg, entry);
988 g_free(msg);
989
990 if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
991 IPMIInterface *s = ibs->parent.intf;
992 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
993
994 ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
995 k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
996 }
997
d13ada5d 998out:
8bfffbcc
CM
999 return;
1000}
1001
1002static unsigned char
1003ipmb_checksum(unsigned char *data, int size, unsigned char csum)
1004{
1005 for (; size > 0; size--, data++) {
1006 csum += *data;
1007 }
1008
1009 return -csum;
1010}
1011
1012static void send_msg(IPMIBmcSim *ibs,
1013 uint8_t *cmd, unsigned int cmd_len,
a580d820 1014 RspBuffer *rsp)
8bfffbcc
CM
1015{
1016 IPMIInterface *s = ibs->parent.intf;
1017 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
1018 IPMIRcvBufEntry *msg;
1019 uint8_t *buf;
1020 uint8_t netfn, rqLun, rsLun, rqSeq;
1021
8bfffbcc
CM
1022 if (cmd[2] != 0) {
1023 /* We only handle channel 0 with no options */
6acb971a 1024 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
d13ada5d 1025 return;
8bfffbcc
CM
1026 }
1027
4f298a4b 1028 if (cmd_len < 10) {
6acb971a 1029 rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
4f298a4b
CLG
1030 return;
1031 }
1032
8bfffbcc
CM
1033 if (cmd[3] != 0x40) {
1034 /* We only emulate a MC at address 0x40. */
6acb971a 1035 rsp_buffer_set_error(rsp, 0x83); /* NAK on write */
d13ada5d 1036 return;
8bfffbcc
CM
1037 }
1038
1039 cmd += 3; /* Skip the header. */
1040 cmd_len -= 3;
1041
1042 /*
1043 * At this point we "send" the message successfully. Any error will
1044 * be returned in the response.
1045 */
1046 if (ipmb_checksum(cmd, cmd_len, 0) != 0 ||
1047 cmd[3] != 0x20) { /* Improper response address */
d13ada5d 1048 return; /* No response */
8bfffbcc
CM
1049 }
1050
1051 netfn = cmd[1] >> 2;
1052 rqLun = cmd[4] & 0x3;
1053 rsLun = cmd[1] & 0x3;
1054 rqSeq = cmd[4] >> 2;
1055
1056 if (rqLun != 2) {
1057 /* We only support LUN 2 coming back to us. */
d13ada5d 1058 return;
8bfffbcc
CM
1059 }
1060
1061 msg = g_malloc(sizeof(*msg));
1062 msg->buf[0] = ((netfn | 1) << 2) | rqLun; /* NetFN, and make a response */
1063 msg->buf[1] = ipmb_checksum(msg->buf, 1, 0);
1064 msg->buf[2] = cmd[0]; /* rsSA */
1065 msg->buf[3] = (rqSeq << 2) | rsLun;
1066 msg->buf[4] = cmd[5]; /* Cmd */
1067 msg->buf[5] = 0; /* Completion Code */
1068 msg->len = 6;
1069
1070 if ((cmd[1] >> 2) != IPMI_NETFN_APP || cmd[5] != IPMI_CMD_GET_DEVICE_ID) {
1071 /* Not a command we handle. */
1072 msg->buf[5] = IPMI_CC_INVALID_CMD;
1073 goto end_msg;
1074 }
1075
1076 buf = msg->buf + msg->len; /* After the CC */
1077 buf[0] = 0;
1078 buf[1] = 0;
1079 buf[2] = 0;
1080 buf[3] = 0;
1081 buf[4] = 0x51;
1082 buf[5] = 0;
1083 buf[6] = 0;
1084 buf[7] = 0;
1085 buf[8] = 0;
1086 buf[9] = 0;
1087 buf[10] = 0;
1088 msg->len += 11;
1089
1090 end_msg:
1091 msg->buf[msg->len] = ipmb_checksum(msg->buf, msg->len, 0);
1092 msg->len++;
8bfffbcc
CM
1093 QTAILQ_INSERT_TAIL(&ibs->rcvbufs, msg, entry);
1094 ibs->msg_flags |= IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
1095 k->set_atn(s, 1, attn_irq_enabled(ibs));
8bfffbcc
CM
1096}
1097
1098static void do_watchdog_reset(IPMIBmcSim *ibs)
1099{
1100 if (IPMI_BMC_WATCHDOG_GET_ACTION(ibs) ==
1101 IPMI_BMC_WATCHDOG_ACTION_NONE) {
1102 ibs->watchdog_running = 0;
1103 return;
1104 }
1105 ibs->watchdog_preaction_ran = 0;
1106
1107
1108 /* Timeout is in tenths of a second, offset is in seconds */
1109 ibs->watchdog_expiry = ipmi_getmonotime();
1110 ibs->watchdog_expiry += ibs->watchdog_timeout * 100000000LL;
1111 if (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs) != IPMI_BMC_WATCHDOG_PRE_NONE) {
1112 ibs->watchdog_expiry -= ibs->watchdog_pretimeout * 1000000000LL;
1113 }
1114 ibs->watchdog_running = 1;
1115}
1116
1117static void reset_watchdog_timer(IPMIBmcSim *ibs,
1118 uint8_t *cmd, unsigned int cmd_len,
a580d820 1119 RspBuffer *rsp)
8bfffbcc
CM
1120{
1121 if (!ibs->watchdog_initialized) {
6acb971a 1122 rsp_buffer_set_error(rsp, 0x80);
d13ada5d 1123 return;
8bfffbcc
CM
1124 }
1125 do_watchdog_reset(ibs);
8bfffbcc
CM
1126}
1127
1128static void set_watchdog_timer(IPMIBmcSim *ibs,
1129 uint8_t *cmd, unsigned int cmd_len,
a580d820 1130 RspBuffer *rsp)
8bfffbcc
CM
1131{
1132 IPMIInterface *s = ibs->parent.intf;
1133 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
1134 unsigned int val;
1135
8bfffbcc
CM
1136 val = cmd[2] & 0x7; /* Validate use */
1137 if (val == 0 || val > 5) {
6acb971a 1138 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
d13ada5d 1139 return;
8bfffbcc
CM
1140 }
1141 val = cmd[3] & 0x7; /* Validate action */
1142 switch (val) {
1143 case IPMI_BMC_WATCHDOG_ACTION_NONE:
1144 break;
1145
1146 case IPMI_BMC_WATCHDOG_ACTION_RESET:
6acb971a 1147 rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 1));
8bfffbcc
CM
1148 break;
1149
1150 case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
6acb971a 1151 rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 1));
8bfffbcc
CM
1152 break;
1153
1154 case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
6acb971a 1155 rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 1));
8bfffbcc
CM
1156 break;
1157
1158 default:
6acb971a 1159 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
8bfffbcc 1160 }
a580d820 1161 if (rsp->buffer[2]) {
6acb971a 1162 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
d13ada5d 1163 return;
8bfffbcc
CM
1164 }
1165
1166 val = (cmd[3] >> 4) & 0x7; /* Validate preaction */
1167 switch (val) {
1168 case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
1169 case IPMI_BMC_WATCHDOG_PRE_NONE:
1170 break;
1171
1172 case IPMI_BMC_WATCHDOG_PRE_NMI:
6af94767 1173 if (k->do_hw_op(s, IPMI_SEND_NMI, 1)) {
8bfffbcc 1174 /* NMI not supported. */
6acb971a 1175 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
d13ada5d 1176 return;
8bfffbcc 1177 }
37eebb86
CM
1178 break;
1179
8bfffbcc
CM
1180 default:
1181 /* We don't support PRE_SMI */
6acb971a 1182 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
d13ada5d 1183 return;
8bfffbcc
CM
1184 }
1185
1186 ibs->watchdog_initialized = 1;
1187 ibs->watchdog_use = cmd[2] & IPMI_BMC_WATCHDOG_USE_MASK;
1188 ibs->watchdog_action = cmd[3] & IPMI_BMC_WATCHDOG_ACTION_MASK;
1189 ibs->watchdog_pretimeout = cmd[4];
1190 ibs->watchdog_expired &= ~cmd[5];
1191 ibs->watchdog_timeout = cmd[6] | (((uint16_t) cmd[7]) << 8);
1192 if (ibs->watchdog_running & IPMI_BMC_WATCHDOG_GET_DONT_STOP(ibs)) {
1193 do_watchdog_reset(ibs);
1194 } else {
1195 ibs->watchdog_running = 0;
1196 }
8bfffbcc
CM
1197}
1198
1199static void get_watchdog_timer(IPMIBmcSim *ibs,
1200 uint8_t *cmd, unsigned int cmd_len,
a580d820 1201 RspBuffer *rsp)
8bfffbcc 1202{
a580d820
CLG
1203 rsp_buffer_push(rsp, ibs->watchdog_use);
1204 rsp_buffer_push(rsp, ibs->watchdog_action);
1205 rsp_buffer_push(rsp, ibs->watchdog_pretimeout);
1206 rsp_buffer_push(rsp, ibs->watchdog_expired);
fb45770b
CM
1207 rsp_buffer_push(rsp, ibs->watchdog_timeout & 0xff);
1208 rsp_buffer_push(rsp, (ibs->watchdog_timeout >> 8) & 0xff);
8bfffbcc
CM
1209 if (ibs->watchdog_running) {
1210 long timeout;
1211 timeout = ((ibs->watchdog_expiry - ipmi_getmonotime() + 50000000)
1212 / 100000000);
a580d820
CLG
1213 rsp_buffer_push(rsp, timeout & 0xff);
1214 rsp_buffer_push(rsp, (timeout >> 8) & 0xff);
8bfffbcc 1215 } else {
a580d820
CLG
1216 rsp_buffer_push(rsp, 0);
1217 rsp_buffer_push(rsp, 0);
8bfffbcc 1218 }
8bfffbcc
CM
1219}
1220
1221static void get_sdr_rep_info(IPMIBmcSim *ibs,
1222 uint8_t *cmd, unsigned int cmd_len,
a580d820 1223 RspBuffer *rsp)
8bfffbcc
CM
1224{
1225 unsigned int i;
1226
a580d820
CLG
1227 rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 spec */
1228 rsp_buffer_push(rsp, ibs->sdr.next_rec_id & 0xff);
1229 rsp_buffer_push(rsp, (ibs->sdr.next_rec_id >> 8) & 0xff);
1230 rsp_buffer_push(rsp, (MAX_SDR_SIZE - ibs->sdr.next_free) & 0xff);
1231 rsp_buffer_push(rsp, ((MAX_SDR_SIZE - ibs->sdr.next_free) >> 8) & 0xff);
8bfffbcc 1232 for (i = 0; i < 4; i++) {
a580d820 1233 rsp_buffer_push(rsp, ibs->sdr.last_addition[i]);
8bfffbcc
CM
1234 }
1235 for (i = 0; i < 4; i++) {
a580d820 1236 rsp_buffer_push(rsp, ibs->sdr.last_clear[i]);
8bfffbcc
CM
1237 }
1238 /* Only modal support, reserve supported */
a580d820 1239 rsp_buffer_push(rsp, (ibs->sdr.overflow << 7) | 0x22);
8bfffbcc
CM
1240}
1241
1242static void reserve_sdr_rep(IPMIBmcSim *ibs,
1243 uint8_t *cmd, unsigned int cmd_len,
a580d820 1244 RspBuffer *rsp)
8bfffbcc 1245{
a580d820
CLG
1246 rsp_buffer_push(rsp, ibs->sdr.reservation & 0xff);
1247 rsp_buffer_push(rsp, (ibs->sdr.reservation >> 8) & 0xff);
8bfffbcc
CM
1248}
1249
1250static void get_sdr(IPMIBmcSim *ibs,
1251 uint8_t *cmd, unsigned int cmd_len,
a580d820 1252 RspBuffer *rsp)
8bfffbcc
CM
1253{
1254 unsigned int pos;
1255 uint16_t nextrec;
a2295f0a 1256 struct ipmi_sdr_header *sdrh;
8bfffbcc 1257
8bfffbcc 1258 if (cmd[6]) {
7f996411 1259 if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) {
6acb971a 1260 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
7f996411
CLG
1261 return;
1262 }
8bfffbcc 1263 }
7f996411 1264
8bfffbcc
CM
1265 pos = 0;
1266 if (sdr_find_entry(&ibs->sdr, cmd[4] | (cmd[5] << 8),
1267 &pos, &nextrec)) {
6acb971a 1268 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
d13ada5d 1269 return;
8bfffbcc 1270 }
a2295f0a
CLG
1271
1272 sdrh = (struct ipmi_sdr_header *) &ibs->sdr.sdr[pos];
1273
1274 if (cmd[6] > ipmi_sdr_length(sdrh)) {
6acb971a 1275 rsp_buffer_set_error(rsp, IPMI_CC_PARM_OUT_OF_RANGE);
d13ada5d 1276 return;
8bfffbcc
CM
1277 }
1278
a580d820
CLG
1279 rsp_buffer_push(rsp, nextrec & 0xff);
1280 rsp_buffer_push(rsp, (nextrec >> 8) & 0xff);
8bfffbcc
CM
1281
1282 if (cmd[7] == 0xff) {
a2295f0a 1283 cmd[7] = ipmi_sdr_length(sdrh) - cmd[6];
8bfffbcc
CM
1284 }
1285
a580d820 1286 if ((cmd[7] + rsp->len) > sizeof(rsp->buffer)) {
6acb971a 1287 rsp_buffer_set_error(rsp, IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES);
d13ada5d 1288 return;
8bfffbcc 1289 }
a580d820
CLG
1290
1291 rsp_buffer_pushmore(rsp, ibs->sdr.sdr + pos + cmd[6], cmd[7]);
8bfffbcc
CM
1292}
1293
1294static void add_sdr(IPMIBmcSim *ibs,
1295 uint8_t *cmd, unsigned int cmd_len,
a580d820 1296 RspBuffer *rsp)
8bfffbcc
CM
1297{
1298 uint16_t recid;
a2295f0a 1299 struct ipmi_sdr_header *sdrh = (struct ipmi_sdr_header *) cmd + 2;
8bfffbcc 1300
a2295f0a 1301 if (sdr_add_entry(ibs, sdrh, cmd_len - 2, &recid)) {
6acb971a 1302 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
d13ada5d 1303 return;
8bfffbcc 1304 }
a580d820
CLG
1305 rsp_buffer_push(rsp, recid & 0xff);
1306 rsp_buffer_push(rsp, (recid >> 8) & 0xff);
8bfffbcc
CM
1307}
1308
1309static void clear_sdr_rep(IPMIBmcSim *ibs,
1310 uint8_t *cmd, unsigned int cmd_len,
a580d820 1311 RspBuffer *rsp)
8bfffbcc 1312{
7f996411 1313 if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) {
6acb971a 1314 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
7f996411
CLG
1315 return;
1316 }
1317
8bfffbcc 1318 if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
6acb971a 1319 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
d13ada5d 1320 return;
8bfffbcc
CM
1321 }
1322 if (cmd[7] == 0xaa) {
1323 ibs->sdr.next_free = 0;
1324 ibs->sdr.overflow = 0;
1325 set_timestamp(ibs, ibs->sdr.last_clear);
a580d820 1326 rsp_buffer_push(rsp, 1); /* Erasure complete */
8bfffbcc
CM
1327 sdr_inc_reservation(&ibs->sdr);
1328 } else if (cmd[7] == 0) {
a580d820 1329 rsp_buffer_push(rsp, 1); /* Erasure complete */
8bfffbcc 1330 } else {
6acb971a 1331 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
d13ada5d 1332 return;
8bfffbcc 1333 }
8bfffbcc
CM
1334}
1335
1336static void get_sel_info(IPMIBmcSim *ibs,
1337 uint8_t *cmd, unsigned int cmd_len,
a580d820 1338 RspBuffer *rsp)
8bfffbcc
CM
1339{
1340 unsigned int i, val;
1341
a580d820
CLG
1342 rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 */
1343 rsp_buffer_push(rsp, ibs->sel.next_free & 0xff);
1344 rsp_buffer_push(rsp, (ibs->sel.next_free >> 8) & 0xff);
8bfffbcc 1345 val = (MAX_SEL_SIZE - ibs->sel.next_free) * 16;
a580d820
CLG
1346 rsp_buffer_push(rsp, val & 0xff);
1347 rsp_buffer_push(rsp, (val >> 8) & 0xff);
8bfffbcc 1348 for (i = 0; i < 4; i++) {
a580d820 1349 rsp_buffer_push(rsp, ibs->sel.last_addition[i]);
8bfffbcc
CM
1350 }
1351 for (i = 0; i < 4; i++) {
a580d820 1352 rsp_buffer_push(rsp, ibs->sel.last_clear[i]);
8bfffbcc
CM
1353 }
1354 /* Only support Reserve SEL */
a580d820 1355 rsp_buffer_push(rsp, (ibs->sel.overflow << 7) | 0x02);
8bfffbcc
CM
1356}
1357
540c07d3
CLG
1358static void get_fru_area_info(IPMIBmcSim *ibs,
1359 uint8_t *cmd, unsigned int cmd_len,
1360 RspBuffer *rsp)
1361{
1362 uint8_t fruid;
1363 uint16_t fru_entry_size;
1364
1365 fruid = cmd[2];
1366
1367 if (fruid >= ibs->fru.nentries) {
1368 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1369 return;
1370 }
1371
1372 fru_entry_size = ibs->fru.areasize;
1373
1374 rsp_buffer_push(rsp, fru_entry_size & 0xff);
1375 rsp_buffer_push(rsp, fru_entry_size >> 8 & 0xff);
1376 rsp_buffer_push(rsp, 0x0);
1377}
1378
1379static void read_fru_data(IPMIBmcSim *ibs,
1380 uint8_t *cmd, unsigned int cmd_len,
1381 RspBuffer *rsp)
1382{
1383 uint8_t fruid;
1384 uint16_t offset;
1385 int i;
1386 uint8_t *fru_entry;
1387 unsigned int count;
1388
1389 fruid = cmd[2];
1390 offset = (cmd[3] | cmd[4] << 8);
1391
1392 if (fruid >= ibs->fru.nentries) {
1393 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1394 return;
1395 }
1396
1397 if (offset >= ibs->fru.areasize - 1) {
1398 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1399 return;
1400 }
1401
1402 fru_entry = &ibs->fru.data[fruid * ibs->fru.areasize];
1403
1404 count = MIN(cmd[5], ibs->fru.areasize - offset);
1405
1406 rsp_buffer_push(rsp, count & 0xff);
1407 for (i = 0; i < count; i++) {
1408 rsp_buffer_push(rsp, fru_entry[offset + i]);
1409 }
1410}
1411
1412static void write_fru_data(IPMIBmcSim *ibs,
1413 uint8_t *cmd, unsigned int cmd_len,
1414 RspBuffer *rsp)
1415{
1416 uint8_t fruid;
1417 uint16_t offset;
1418 uint8_t *fru_entry;
1419 unsigned int count;
1420
1421 fruid = cmd[2];
1422 offset = (cmd[3] | cmd[4] << 8);
1423
1424 if (fruid >= ibs->fru.nentries) {
1425 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1426 return;
1427 }
1428
1429 if (offset >= ibs->fru.areasize - 1) {
1430 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1431 return;
1432 }
1433
1434 fru_entry = &ibs->fru.data[fruid * ibs->fru.areasize];
1435
1436 count = MIN(cmd_len - 5, ibs->fru.areasize - offset);
1437
1438 memcpy(fru_entry + offset, cmd + 5, count);
1439
1440 rsp_buffer_push(rsp, count & 0xff);
1441}
1442
8bfffbcc
CM
1443static void reserve_sel(IPMIBmcSim *ibs,
1444 uint8_t *cmd, unsigned int cmd_len,
a580d820 1445 RspBuffer *rsp)
8bfffbcc 1446{
a580d820
CLG
1447 rsp_buffer_push(rsp, ibs->sel.reservation & 0xff);
1448 rsp_buffer_push(rsp, (ibs->sel.reservation >> 8) & 0xff);
8bfffbcc
CM
1449}
1450
1451static void get_sel_entry(IPMIBmcSim *ibs,
1452 uint8_t *cmd, unsigned int cmd_len,
a580d820 1453 RspBuffer *rsp)
8bfffbcc
CM
1454{
1455 unsigned int val;
1456
8bfffbcc 1457 if (cmd[6]) {
7f996411 1458 if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) {
6acb971a 1459 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
7f996411
CLG
1460 return;
1461 }
8bfffbcc
CM
1462 }
1463 if (ibs->sel.next_free == 0) {
6acb971a 1464 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
d13ada5d 1465 return;
8bfffbcc
CM
1466 }
1467 if (cmd[6] > 15) {
6acb971a 1468 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
d13ada5d 1469 return;
8bfffbcc
CM
1470 }
1471 if (cmd[7] == 0xff) {
1472 cmd[7] = 16;
1473 } else if ((cmd[7] + cmd[6]) > 16) {
6acb971a 1474 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
d13ada5d 1475 return;
8bfffbcc
CM
1476 } else {
1477 cmd[7] += cmd[6];
1478 }
1479
1480 val = cmd[4] | (cmd[5] << 8);
1481 if (val == 0xffff) {
1482 val = ibs->sel.next_free - 1;
1483 } else if (val >= ibs->sel.next_free) {
6acb971a 1484 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
d13ada5d 1485 return;
8bfffbcc
CM
1486 }
1487 if ((val + 1) == ibs->sel.next_free) {
a580d820
CLG
1488 rsp_buffer_push(rsp, 0xff);
1489 rsp_buffer_push(rsp, 0xff);
8bfffbcc 1490 } else {
a580d820
CLG
1491 rsp_buffer_push(rsp, (val + 1) & 0xff);
1492 rsp_buffer_push(rsp, ((val + 1) >> 8) & 0xff);
8bfffbcc
CM
1493 }
1494 for (; cmd[6] < cmd[7]; cmd[6]++) {
a580d820 1495 rsp_buffer_push(rsp, ibs->sel.sel[val][cmd[6]]);
8bfffbcc 1496 }
8bfffbcc
CM
1497}
1498
1499static void add_sel_entry(IPMIBmcSim *ibs,
1500 uint8_t *cmd, unsigned int cmd_len,
a580d820 1501 RspBuffer *rsp)
8bfffbcc 1502{
8bfffbcc 1503 if (sel_add_event(ibs, cmd + 2)) {
6acb971a 1504 rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE);
d13ada5d 1505 return;
8bfffbcc
CM
1506 }
1507 /* sel_add_event fills in the record number. */
a580d820
CLG
1508 rsp_buffer_push(rsp, cmd[2]);
1509 rsp_buffer_push(rsp, cmd[3]);
8bfffbcc
CM
1510}
1511
1512static void clear_sel(IPMIBmcSim *ibs,
1513 uint8_t *cmd, unsigned int cmd_len,
a580d820 1514 RspBuffer *rsp)
8bfffbcc 1515{
7f996411 1516 if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) {
6acb971a 1517 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
7f996411
CLG
1518 return;
1519 }
1520
8bfffbcc 1521 if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
6acb971a 1522 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
d13ada5d 1523 return;
8bfffbcc
CM
1524 }
1525 if (cmd[7] == 0xaa) {
1526 ibs->sel.next_free = 0;
1527 ibs->sel.overflow = 0;
1528 set_timestamp(ibs, ibs->sdr.last_clear);
a580d820 1529 rsp_buffer_push(rsp, 1); /* Erasure complete */
8bfffbcc
CM
1530 sel_inc_reservation(&ibs->sel);
1531 } else if (cmd[7] == 0) {
a580d820 1532 rsp_buffer_push(rsp, 1); /* Erasure complete */
8bfffbcc 1533 } else {
6acb971a 1534 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
d13ada5d 1535 return;
8bfffbcc 1536 }
8bfffbcc
CM
1537}
1538
1539static void get_sel_time(IPMIBmcSim *ibs,
1540 uint8_t *cmd, unsigned int cmd_len,
a580d820 1541 RspBuffer *rsp)
8bfffbcc
CM
1542{
1543 uint32_t val;
1544 struct ipmi_time now;
1545
1546 ipmi_gettime(&now);
1547 val = now.tv_sec + ibs->sel.time_offset;
a580d820
CLG
1548 rsp_buffer_push(rsp, val & 0xff);
1549 rsp_buffer_push(rsp, (val >> 8) & 0xff);
1550 rsp_buffer_push(rsp, (val >> 16) & 0xff);
1551 rsp_buffer_push(rsp, (val >> 24) & 0xff);
8bfffbcc
CM
1552}
1553
1554static void set_sel_time(IPMIBmcSim *ibs,
1555 uint8_t *cmd, unsigned int cmd_len,
a580d820 1556 RspBuffer *rsp)
8bfffbcc
CM
1557{
1558 uint32_t val;
1559 struct ipmi_time now;
1560
8bfffbcc
CM
1561 val = cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24);
1562 ipmi_gettime(&now);
1563 ibs->sel.time_offset = now.tv_sec - ((long) val);
8bfffbcc
CM
1564}
1565
9380d2ed
CM
1566static void platform_event_msg(IPMIBmcSim *ibs,
1567 uint8_t *cmd, unsigned int cmd_len,
1568 RspBuffer *rsp)
1569{
1570 uint8_t event[16];
1571
1572 event[2] = 2; /* System event record */
1573 event[7] = cmd[2]; /* Generator ID */
1574 event[8] = 0;
1575 event[9] = cmd[3]; /* EvMRev */
1576 event[10] = cmd[4]; /* Sensor type */
1577 event[11] = cmd[5]; /* Sensor number */
1578 event[12] = cmd[6]; /* Event dir / Event type */
1579 event[13] = cmd[7]; /* Event data 1 */
1580 event[14] = cmd[8]; /* Event data 2 */
1581 event[15] = cmd[9]; /* Event data 3 */
1582
1583 if (sel_add_event(ibs, event)) {
1584 rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE);
1585 }
1586}
1587
8bfffbcc
CM
1588static void set_sensor_evt_enable(IPMIBmcSim *ibs,
1589 uint8_t *cmd, unsigned int cmd_len,
a580d820 1590 RspBuffer *rsp)
8bfffbcc
CM
1591{
1592 IPMISensor *sens;
1593
73d60fa5 1594 if ((cmd[2] >= MAX_SENSORS) ||
8bfffbcc 1595 !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
6acb971a 1596 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
d13ada5d 1597 return;
8bfffbcc
CM
1598 }
1599 sens = ibs->sensors + cmd[2];
1600 switch ((cmd[3] >> 4) & 0x3) {
1601 case 0: /* Do not change */
1602 break;
1603 case 1: /* Enable bits */
1604 if (cmd_len > 4) {
1605 sens->assert_enable |= cmd[4];
1606 }
1607 if (cmd_len > 5) {
1608 sens->assert_enable |= cmd[5] << 8;
1609 }
1610 if (cmd_len > 6) {
1611 sens->deassert_enable |= cmd[6];
1612 }
1613 if (cmd_len > 7) {
1614 sens->deassert_enable |= cmd[7] << 8;
1615 }
1616 break;
1617 case 2: /* Disable bits */
1618 if (cmd_len > 4) {
1619 sens->assert_enable &= ~cmd[4];
1620 }
1621 if (cmd_len > 5) {
1622 sens->assert_enable &= ~(cmd[5] << 8);
1623 }
1624 if (cmd_len > 6) {
1625 sens->deassert_enable &= ~cmd[6];
1626 }
1627 if (cmd_len > 7) {
1628 sens->deassert_enable &= ~(cmd[7] << 8);
1629 }
1630 break;
1631 case 3:
6acb971a 1632 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
d13ada5d 1633 return;
8bfffbcc
CM
1634 }
1635 IPMI_SENSOR_SET_RET_STATUS(sens, cmd[3]);
8bfffbcc
CM
1636}
1637
1638static void get_sensor_evt_enable(IPMIBmcSim *ibs,
1639 uint8_t *cmd, unsigned int cmd_len,
a580d820 1640 RspBuffer *rsp)
8bfffbcc
CM
1641{
1642 IPMISensor *sens;
1643
73d60fa5 1644 if ((cmd[2] >= MAX_SENSORS) ||
8bfffbcc 1645 !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
6acb971a 1646 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
d13ada5d 1647 return;
8bfffbcc
CM
1648 }
1649 sens = ibs->sensors + cmd[2];
a580d820
CLG
1650 rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1651 rsp_buffer_push(rsp, sens->assert_enable & 0xff);
1652 rsp_buffer_push(rsp, (sens->assert_enable >> 8) & 0xff);
1653 rsp_buffer_push(rsp, sens->deassert_enable & 0xff);
1654 rsp_buffer_push(rsp, (sens->deassert_enable >> 8) & 0xff);
8bfffbcc
CM
1655}
1656
1657static void rearm_sensor_evts(IPMIBmcSim *ibs,
1658 uint8_t *cmd, unsigned int cmd_len,
a580d820 1659 RspBuffer *rsp)
8bfffbcc
CM
1660{
1661 IPMISensor *sens;
1662
73d60fa5 1663 if ((cmd[2] >= MAX_SENSORS) ||
8bfffbcc 1664 !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
6acb971a 1665 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
d13ada5d 1666 return;
8bfffbcc
CM
1667 }
1668 sens = ibs->sensors + cmd[2];
1669
1670 if ((cmd[3] & 0x80) == 0) {
1671 /* Just clear everything */
1672 sens->states = 0;
d13ada5d 1673 return;
8bfffbcc 1674 }
8bfffbcc
CM
1675}
1676
1677static void get_sensor_evt_status(IPMIBmcSim *ibs,
1678 uint8_t *cmd, unsigned int cmd_len,
a580d820 1679 RspBuffer *rsp)
8bfffbcc
CM
1680{
1681 IPMISensor *sens;
1682
73d60fa5 1683 if ((cmd[2] >= MAX_SENSORS) ||
8bfffbcc 1684 !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
6acb971a 1685 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
d13ada5d 1686 return;
8bfffbcc
CM
1687 }
1688 sens = ibs->sensors + cmd[2];
a580d820
CLG
1689 rsp_buffer_push(rsp, sens->reading);
1690 rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1691 rsp_buffer_push(rsp, sens->assert_states & 0xff);
1692 rsp_buffer_push(rsp, (sens->assert_states >> 8) & 0xff);
1693 rsp_buffer_push(rsp, sens->deassert_states & 0xff);
1694 rsp_buffer_push(rsp, (sens->deassert_states >> 8) & 0xff);
8bfffbcc
CM
1695}
1696
1697static void get_sensor_reading(IPMIBmcSim *ibs,
1698 uint8_t *cmd, unsigned int cmd_len,
a580d820 1699 RspBuffer *rsp)
8bfffbcc
CM
1700{
1701 IPMISensor *sens;
1702
73d60fa5 1703 if ((cmd[2] >= MAX_SENSORS) ||
8bfffbcc 1704 !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
6acb971a 1705 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
d13ada5d 1706 return;
8bfffbcc
CM
1707 }
1708 sens = ibs->sensors + cmd[2];
a580d820
CLG
1709 rsp_buffer_push(rsp, sens->reading);
1710 rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1711 rsp_buffer_push(rsp, sens->states & 0xff);
8bfffbcc 1712 if (IPMI_SENSOR_IS_DISCRETE(sens)) {
a580d820 1713 rsp_buffer_push(rsp, (sens->states >> 8) & 0xff);
8bfffbcc 1714 }
8bfffbcc
CM
1715}
1716
728710e1 1717static void set_sensor_type(IPMIBmcSim *ibs,
a580d820
CLG
1718 uint8_t *cmd, unsigned int cmd_len,
1719 RspBuffer *rsp)
728710e1
CLG
1720{
1721 IPMISensor *sens;
1722
1723
73d60fa5 1724 if ((cmd[2] >= MAX_SENSORS) ||
728710e1 1725 !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
6acb971a 1726 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
728710e1
CLG
1727 return;
1728 }
1729 sens = ibs->sensors + cmd[2];
1730 sens->sensor_type = cmd[3];
1731 sens->evt_reading_type_code = cmd[4] & 0x7f;
1732}
1733
1734static void get_sensor_type(IPMIBmcSim *ibs,
a580d820
CLG
1735 uint8_t *cmd, unsigned int cmd_len,
1736 RspBuffer *rsp)
728710e1
CLG
1737{
1738 IPMISensor *sens;
1739
1740
73d60fa5 1741 if ((cmd[2] >= MAX_SENSORS) ||
728710e1 1742 !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
6acb971a 1743 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
728710e1
CLG
1744 return;
1745 }
1746 sens = ibs->sensors + cmd[2];
a580d820
CLG
1747 rsp_buffer_push(rsp, sens->sensor_type);
1748 rsp_buffer_push(rsp, sens->evt_reading_type_code);
728710e1
CLG
1749}
1750
e3f7320c
CLG
1751/*
1752 * bytes parameter
1753 * 1 sensor number
1754 * 2 operation (see below for bits meaning)
1755 * 3 sensor reading
1756 * 4:5 assertion states (optional)
1757 * 6:7 deassertion states (optional)
1758 * 8:10 event data 1,2,3 (optional)
1759 */
1760static void set_sensor_reading(IPMIBmcSim *ibs,
1761 uint8_t *cmd, unsigned int cmd_len,
1762 RspBuffer *rsp)
1763{
1764 IPMISensor *sens;
1765 uint8_t evd1 = 0;
1766 uint8_t evd2 = 0;
1767 uint8_t evd3 = 0;
1768 uint8_t new_reading = 0;
1769 uint16_t new_assert_states = 0;
1770 uint16_t new_deassert_states = 0;
1771 bool change_reading = false;
1772 bool change_assert = false;
1773 bool change_deassert = false;
1774 enum {
1775 SENSOR_GEN_EVENT_NONE,
1776 SENSOR_GEN_EVENT_DATA,
1777 SENSOR_GEN_EVENT_BMC,
1778 } do_gen_event = SENSOR_GEN_EVENT_NONE;
1779
1780 if ((cmd[2] >= MAX_SENSORS) ||
1781 !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1782 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1783 return;
1784 }
1785
1786 sens = ibs->sensors + cmd[2];
1787
1788 /* [1:0] Sensor Reading operation */
1789 switch ((cmd[3]) & 0x3) {
1790 case 0: /* Do not change */
1791 break;
1792 case 1: /* write given value to sensor reading byte */
1793 new_reading = cmd[4];
1794 if (sens->reading != new_reading) {
1795 change_reading = true;
1796 }
1797 break;
1798 case 2:
1799 case 3:
1800 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1801 return;
1802 }
1803
1804 /* [3:2] Deassertion bits operation */
1805 switch ((cmd[3] >> 2) & 0x3) {
1806 case 0: /* Do not change */
1807 break;
1808 case 1: /* write given value */
1809 if (cmd_len > 7) {
1810 new_deassert_states = cmd[7];
1811 change_deassert = true;
1812 }
1813 if (cmd_len > 8) {
1814 new_deassert_states |= (cmd[8] << 8);
1815 }
1816 break;
1817
1818 case 2: /* mask on */
1819 if (cmd_len > 7) {
1820 new_deassert_states = (sens->deassert_states | cmd[7]);
1821 change_deassert = true;
1822 }
1823 if (cmd_len > 8) {
1824 new_deassert_states |= (sens->deassert_states | (cmd[8] << 8));
1825 }
1826 break;
1827
1828 case 3: /* mask off */
1829 if (cmd_len > 7) {
1830 new_deassert_states = (sens->deassert_states & cmd[7]);
1831 change_deassert = true;
1832 }
1833 if (cmd_len > 8) {
1834 new_deassert_states |= (sens->deassert_states & (cmd[8] << 8));
1835 }
1836 break;
1837 }
1838
1839 if (change_deassert && (new_deassert_states == sens->deassert_states)) {
1840 change_deassert = false;
1841 }
1842
1843 /* [5:4] Assertion bits operation */
1844 switch ((cmd[3] >> 4) & 0x3) {
1845 case 0: /* Do not change */
1846 break;
1847 case 1: /* write given value */
1848 if (cmd_len > 5) {
1849 new_assert_states = cmd[5];
1850 change_assert = true;
1851 }
1852 if (cmd_len > 6) {
1853 new_assert_states |= (cmd[6] << 8);
1854 }
1855 break;
1856
1857 case 2: /* mask on */
1858 if (cmd_len > 5) {
1859 new_assert_states = (sens->assert_states | cmd[5]);
1860 change_assert = true;
1861 }
1862 if (cmd_len > 6) {
1863 new_assert_states |= (sens->assert_states | (cmd[6] << 8));
1864 }
1865 break;
1866
1867 case 3: /* mask off */
1868 if (cmd_len > 5) {
1869 new_assert_states = (sens->assert_states & cmd[5]);
1870 change_assert = true;
1871 }
1872 if (cmd_len > 6) {
1873 new_assert_states |= (sens->assert_states & (cmd[6] << 8));
1874 }
1875 break;
1876 }
1877
1878 if (change_assert && (new_assert_states == sens->assert_states)) {
1879 change_assert = false;
1880 }
1881
1882 if (cmd_len > 9) {
1883 evd1 = cmd[9];
1884 }
1885 if (cmd_len > 10) {
1886 evd2 = cmd[10];
1887 }
1888 if (cmd_len > 11) {
1889 evd3 = cmd[11];
1890 }
1891
1892 /* [7:6] Event Data Bytes operation */
1893 switch ((cmd[3] >> 6) & 0x3) {
1894 case 0: /*
1895 * Don’t use Event Data bytes from this command. BMC will
1896 * generate it's own Event Data bytes based on its sensor
1897 * implementation.
1898 */
1899 evd1 = evd2 = evd3 = 0x0;
1900 do_gen_event = SENSOR_GEN_EVENT_BMC;
1901 break;
1902 case 1: /*
1903 * Write given values to event data bytes including bits
1904 * [3:0] Event Data 1.
1905 */
1906 do_gen_event = SENSOR_GEN_EVENT_DATA;
1907 break;
1908 case 2: /*
1909 * Write given values to event data bytes excluding bits
1910 * [3:0] Event Data 1.
1911 */
1912 evd1 &= 0xf0;
1913 do_gen_event = SENSOR_GEN_EVENT_DATA;
1914 break;
1915 case 3:
1916 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1917 return;
1918 }
1919
1920 /*
1921 * Event Data Bytes operation and parameter are inconsistent. The
1922 * Specs are not clear on that topic but generating an error seems
1923 * correct.
1924 */
1925 if (do_gen_event == SENSOR_GEN_EVENT_DATA && cmd_len < 10) {
1926 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1927 return;
1928 }
1929
1930 /* commit values */
1931 if (change_reading) {
1932 sens->reading = new_reading;
1933 }
1934
1935 if (change_assert) {
1936 sens->assert_states = new_assert_states;
1937 }
1938
1939 if (change_deassert) {
1940 sens->deassert_states = new_deassert_states;
1941 }
1942
1943 /* TODO: handle threshold sensor */
1944 if (!IPMI_SENSOR_IS_DISCRETE(sens)) {
1945 return;
1946 }
1947
1948 switch (do_gen_event) {
1949 case SENSOR_GEN_EVENT_DATA: {
1950 unsigned int bit = evd1 & 0xf;
1951 uint16_t mask = (1 << bit);
1952
1953 if (sens->assert_states & mask & sens->assert_enable) {
1954 gen_event(ibs, cmd[2], 0, evd1, evd2, evd3);
1955 }
1956
1957 if (sens->deassert_states & mask & sens->deassert_enable) {
1958 gen_event(ibs, cmd[2], 1, evd1, evd2, evd3);
1959 }
1960 break;
1961 }
1962 case SENSOR_GEN_EVENT_BMC:
1963 /*
1964 * TODO: generate event and event data bytes depending on the
1965 * sensor
1966 */
1967 break;
1968 case SENSOR_GEN_EVENT_NONE:
1969 break;
1970 }
1971}
728710e1 1972
62a4931d 1973static const IPMICmdHandler chassis_cmds[] = {
4f298a4b
CLG
1974 [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = { chassis_capabilities },
1975 [IPMI_CMD_GET_CHASSIS_STATUS] = { chassis_status },
1976 [IPMI_CMD_CHASSIS_CONTROL] = { chassis_control, 3 },
1977 [IPMI_CMD_GET_SYS_RESTART_CAUSE] = { chassis_get_sys_restart_cause }
8bfffbcc
CM
1978};
1979static const IPMINetfn chassis_netfn = {
62a4931d 1980 .cmd_nums = ARRAY_SIZE(chassis_cmds),
8bfffbcc
CM
1981 .cmd_handlers = chassis_cmds
1982};
1983
62a4931d 1984static const IPMICmdHandler sensor_event_cmds[] = {
9380d2ed 1985 [IPMI_CMD_PLATFORM_EVENT_MSG] = { platform_event_msg, 10 },
4f298a4b
CLG
1986 [IPMI_CMD_SET_SENSOR_EVT_ENABLE] = { set_sensor_evt_enable, 4 },
1987 [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = { get_sensor_evt_enable, 3 },
1988 [IPMI_CMD_REARM_SENSOR_EVTS] = { rearm_sensor_evts, 4 },
1989 [IPMI_CMD_GET_SENSOR_EVT_STATUS] = { get_sensor_evt_status, 3 },
1990 [IPMI_CMD_GET_SENSOR_READING] = { get_sensor_reading, 3 },
1991 [IPMI_CMD_SET_SENSOR_TYPE] = { set_sensor_type, 5 },
1992 [IPMI_CMD_GET_SENSOR_TYPE] = { get_sensor_type, 3 },
e3f7320c 1993 [IPMI_CMD_SET_SENSOR_READING] = { set_sensor_reading, 5 },
8bfffbcc
CM
1994};
1995static const IPMINetfn sensor_event_netfn = {
62a4931d 1996 .cmd_nums = ARRAY_SIZE(sensor_event_cmds),
8bfffbcc
CM
1997 .cmd_handlers = sensor_event_cmds
1998};
1999
62a4931d 2000static const IPMICmdHandler app_cmds[] = {
4f298a4b
CLG
2001 [IPMI_CMD_GET_DEVICE_ID] = { get_device_id },
2002 [IPMI_CMD_COLD_RESET] = { cold_reset },
2003 [IPMI_CMD_WARM_RESET] = { warm_reset },
2004 [IPMI_CMD_SET_ACPI_POWER_STATE] = { set_acpi_power_state, 4 },
2005 [IPMI_CMD_GET_ACPI_POWER_STATE] = { get_acpi_power_state },
2006 [IPMI_CMD_GET_DEVICE_GUID] = { get_device_guid },
2007 [IPMI_CMD_SET_BMC_GLOBAL_ENABLES] = { set_bmc_global_enables, 3 },
2008 [IPMI_CMD_GET_BMC_GLOBAL_ENABLES] = { get_bmc_global_enables },
2009 [IPMI_CMD_CLR_MSG_FLAGS] = { clr_msg_flags, 3 },
2010 [IPMI_CMD_GET_MSG_FLAGS] = { get_msg_flags },
2011 [IPMI_CMD_GET_MSG] = { get_msg },
2012 [IPMI_CMD_SEND_MSG] = { send_msg, 3 },
2013 [IPMI_CMD_READ_EVT_MSG_BUF] = { read_evt_msg_buf },
2014 [IPMI_CMD_RESET_WATCHDOG_TIMER] = { reset_watchdog_timer },
2015 [IPMI_CMD_SET_WATCHDOG_TIMER] = { set_watchdog_timer, 8 },
2016 [IPMI_CMD_GET_WATCHDOG_TIMER] = { get_watchdog_timer },
8bfffbcc
CM
2017};
2018static const IPMINetfn app_netfn = {
62a4931d 2019 .cmd_nums = ARRAY_SIZE(app_cmds),
8bfffbcc
CM
2020 .cmd_handlers = app_cmds
2021};
2022
62a4931d 2023static const IPMICmdHandler storage_cmds[] = {
540c07d3
CLG
2024 [IPMI_CMD_GET_FRU_AREA_INFO] = { get_fru_area_info, 3 },
2025 [IPMI_CMD_READ_FRU_DATA] = { read_fru_data, 5 },
2026 [IPMI_CMD_WRITE_FRU_DATA] = { write_fru_data, 5 },
4f298a4b
CLG
2027 [IPMI_CMD_GET_SDR_REP_INFO] = { get_sdr_rep_info },
2028 [IPMI_CMD_RESERVE_SDR_REP] = { reserve_sdr_rep },
2029 [IPMI_CMD_GET_SDR] = { get_sdr, 8 },
2030 [IPMI_CMD_ADD_SDR] = { add_sdr },
2031 [IPMI_CMD_CLEAR_SDR_REP] = { clear_sdr_rep, 8 },
2032 [IPMI_CMD_GET_SEL_INFO] = { get_sel_info },
2033 [IPMI_CMD_RESERVE_SEL] = { reserve_sel },
2034 [IPMI_CMD_GET_SEL_ENTRY] = { get_sel_entry, 8 },
2035 [IPMI_CMD_ADD_SEL_ENTRY] = { add_sel_entry, 18 },
2036 [IPMI_CMD_CLEAR_SEL] = { clear_sel, 8 },
7f11cb65
CM
2037 [IPMI_CMD_GET_SEL_TIME] = { get_sel_time },
2038 [IPMI_CMD_SET_SEL_TIME] = { set_sel_time, 6 },
8bfffbcc
CM
2039};
2040
2041static const IPMINetfn storage_netfn = {
62a4931d 2042 .cmd_nums = ARRAY_SIZE(storage_cmds),
8bfffbcc
CM
2043 .cmd_handlers = storage_cmds
2044};
2045
2046static void register_cmds(IPMIBmcSim *s)
2047{
ed8da05c
CLG
2048 ipmi_sim_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn);
2049 ipmi_sim_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn);
2050 ipmi_sim_register_netfn(s, IPMI_NETFN_APP, &app_netfn);
2051 ipmi_sim_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn);
8bfffbcc
CM
2052}
2053
5167560b 2054static uint8_t init_sdrs[] = {
8bfffbcc
CM
2055 /* Watchdog device */
2056 0x00, 0x00, 0x51, 0x02, 35, 0x20, 0x00, 0x00,
2057 0x23, 0x01, 0x63, 0x00, 0x23, 0x6f, 0x0f, 0x01,
2058 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2059 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8,
2060 'W', 'a', 't', 'c', 'h', 'd', 'o', 'g',
8bfffbcc
CM
2061};
2062
4fa9f08e
CLG
2063static void ipmi_sdr_init(IPMIBmcSim *ibs)
2064{
2065 unsigned int i;
52fc01d9 2066 int len;
5167560b
CLG
2067 size_t sdrs_size;
2068 uint8_t *sdrs;
4fa9f08e 2069
5167560b
CLG
2070 sdrs_size = sizeof(init_sdrs);
2071 sdrs = init_sdrs;
8c6fd7f3
CLG
2072 if (ibs->sdr_filename &&
2073 !g_file_get_contents(ibs->sdr_filename, (gchar **) &sdrs, &sdrs_size,
2074 NULL)) {
2075 error_report("failed to load sdr file '%s'", ibs->sdr_filename);
2076 sdrs_size = sizeof(init_sdrs);
2077 sdrs = init_sdrs;
2078 }
5167560b
CLG
2079
2080 for (i = 0; i < sdrs_size; i += len) {
4fa9f08e 2081 struct ipmi_sdr_header *sdrh;
52fc01d9 2082
5167560b 2083 if (i + IPMI_SDR_HEADER_SIZE > sdrs_size) {
4fa9f08e 2084 error_report("Problem with recid 0x%4.4x", i);
8c6fd7f3 2085 break;
4fa9f08e 2086 }
5167560b 2087 sdrh = (struct ipmi_sdr_header *) &sdrs[i];
4fa9f08e 2088 len = ipmi_sdr_length(sdrh);
5167560b 2089 if (i + len > sdrs_size) {
4fa9f08e 2090 error_report("Problem with recid 0x%4.4x", i);
8c6fd7f3 2091 break;
4fa9f08e
CLG
2092 }
2093 sdr_add_entry(ibs, sdrh, len, NULL);
4fa9f08e 2094 }
8c6fd7f3
CLG
2095
2096 if (sdrs != init_sdrs) {
2097 g_free(sdrs);
2098 }
4fa9f08e
CLG
2099}
2100
bd66bcfc
CM
2101static const VMStateDescription vmstate_ipmi_sim = {
2102 .name = TYPE_IPMI_BMC_SIMULATOR,
2103 .version_id = 1,
2104 .minimum_version_id = 1,
2105 .fields = (VMStateField[]) {
2106 VMSTATE_UINT8(bmc_global_enables, IPMIBmcSim),
2107 VMSTATE_UINT8(msg_flags, IPMIBmcSim),
2108 VMSTATE_BOOL(watchdog_initialized, IPMIBmcSim),
2109 VMSTATE_UINT8(watchdog_use, IPMIBmcSim),
2110 VMSTATE_UINT8(watchdog_action, IPMIBmcSim),
2111 VMSTATE_UINT8(watchdog_pretimeout, IPMIBmcSim),
2112 VMSTATE_BOOL(watchdog_expired, IPMIBmcSim),
2113 VMSTATE_UINT16(watchdog_timeout, IPMIBmcSim),
2114 VMSTATE_BOOL(watchdog_running, IPMIBmcSim),
2115 VMSTATE_BOOL(watchdog_preaction_ran, IPMIBmcSim),
2116 VMSTATE_INT64(watchdog_expiry, IPMIBmcSim),
2117 VMSTATE_UINT8_ARRAY(evtbuf, IPMIBmcSim, 16),
2118 VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].status, IPMIBmcSim),
2119 VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].reading, IPMIBmcSim),
2120 VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].states, IPMIBmcSim),
2121 VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_states, IPMIBmcSim),
2122 VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].deassert_states,
2123 IPMIBmcSim),
2124 VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_enable, IPMIBmcSim),
2125 VMSTATE_END_OF_LIST()
2126 }
2127};
2128
540c07d3
CLG
2129static void ipmi_fru_init(IPMIFru *fru)
2130{
2131 int fsize;
2132 int size = 0;
2133
2134 if (!fru->filename) {
2135 goto out;
2136 }
2137
2138 fsize = get_image_size(fru->filename);
2139 if (fsize > 0) {
2140 size = QEMU_ALIGN_UP(fsize, fru->areasize);
2141 fru->data = g_malloc0(size);
2142 if (load_image_size(fru->filename, fru->data, fsize) != fsize) {
2143 error_report("Could not load file '%s'", fru->filename);
2144 g_free(fru->data);
2145 fru->data = NULL;
2146 }
2147 }
2148
2149out:
2150 if (!fru->data) {
2151 /* give one default FRU */
2152 size = fru->areasize;
2153 fru->data = g_malloc0(size);
2154 }
2155
2156 fru->nentries = size / fru->areasize;
2157}
2158
0bc6001f 2159static void ipmi_sim_realize(DeviceState *dev, Error **errp)
8bfffbcc 2160{
0bc6001f 2161 IPMIBmc *b = IPMI_BMC(dev);
8bfffbcc 2162 unsigned int i;
8bfffbcc
CM
2163 IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
2164
8bfffbcc
CM
2165 QTAILQ_INIT(&ibs->rcvbufs);
2166
2167 ibs->bmc_global_enables = (1 << IPMI_BMC_EVENT_LOG_BIT);
2168 ibs->device_id = 0x20;
2169 ibs->ipmi_version = 0x02; /* IPMI 2.0 */
b7088392 2170 ibs->restart_cause = 0;
8bfffbcc
CM
2171 for (i = 0; i < 4; i++) {
2172 ibs->sel.last_addition[i] = 0xff;
2173 ibs->sel.last_clear[i] = 0xff;
2174 ibs->sdr.last_addition[i] = 0xff;
2175 ibs->sdr.last_clear[i] = 0xff;
2176 }
2177
4fa9f08e 2178 ipmi_sdr_init(ibs);
8bfffbcc 2179
540c07d3
CLG
2180 ipmi_fru_init(&ibs->fru);
2181
52ba4d50
CLG
2182 ibs->acpi_power_state[0] = 0;
2183 ibs->acpi_power_state[1] = 0;
2184
8bfffbcc
CM
2185 ipmi_init_sensors_from_sdrs(ibs);
2186 register_cmds(ibs);
2187
2188 ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs);
bd66bcfc
CM
2189
2190 vmstate_register(NULL, 0, &vmstate_ipmi_sim, ibs);
8bfffbcc
CM
2191}
2192
8c6fd7f3 2193static Property ipmi_sim_properties[] = {
540c07d3
CLG
2194 DEFINE_PROP_UINT16("fruareasize", IPMIBmcSim, fru.areasize, 1024),
2195 DEFINE_PROP_STRING("frudatafile", IPMIBmcSim, fru.filename),
8c6fd7f3 2196 DEFINE_PROP_STRING("sdrfile", IPMIBmcSim, sdr_filename),
20b23364
CM
2197 DEFINE_PROP_UINT8("device_id", IPMIBmcSim, device_id, 0x20),
2198 DEFINE_PROP_UINT8("ipmi_version", IPMIBmcSim, ipmi_version, 0x02),
2199 DEFINE_PROP_UINT8("device_rev", IPMIBmcSim, device_rev, 0),
2200 DEFINE_PROP_UINT8("fwrev1", IPMIBmcSim, fwrev1, 0),
2201 DEFINE_PROP_UINT8("fwrev2", IPMIBmcSim, fwrev2, 0),
2202 DEFINE_PROP_UINT32("mfg_id", IPMIBmcSim, mfg_id, 0),
2203 DEFINE_PROP_UINT16("product_id", IPMIBmcSim, product_id, 0),
7b0cd78b 2204 DEFINE_PROP_UUID_NODEFAULT("guid", IPMIBmcSim, uuid),
8c6fd7f3
CLG
2205 DEFINE_PROP_END_OF_LIST(),
2206};
2207
8bfffbcc
CM
2208static void ipmi_sim_class_init(ObjectClass *oc, void *data)
2209{
0bc6001f 2210 DeviceClass *dc = DEVICE_CLASS(oc);
8bfffbcc
CM
2211 IPMIBmcClass *bk = IPMI_BMC_CLASS(oc);
2212
66abfddb 2213 dc->hotpluggable = false;
0bc6001f 2214 dc->realize = ipmi_sim_realize;
4f67d30b 2215 device_class_set_props(dc, ipmi_sim_properties);
8bfffbcc
CM
2216 bk->handle_command = ipmi_sim_handle_command;
2217}
2218
2219static const TypeInfo ipmi_sim_type = {
2220 .name = TYPE_IPMI_BMC_SIMULATOR,
2221 .parent = TYPE_IPMI_BMC,
2222 .instance_size = sizeof(IPMIBmcSim),
8bfffbcc
CM
2223 .class_init = ipmi_sim_class_init,
2224};
2225
2226static void ipmi_sim_register_types(void)
2227{
2228 type_register_static(&ipmi_sim_type);
2229}
2230
2231type_init(ipmi_sim_register_types)
This page took 0.536916 seconds and 4 git commands to generate.