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