blob: 55fb81fa5a9bd8a9b18f2de970678bb28fccd1d8 [file] [log] [blame]
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001/*
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
Peter Maydell04308912016-01-26 18:17:30 +000025#include "qemu/osdep.h"
Cédric Le Goater52ba4d52016-01-25 15:07:34 +010026#include "sysemu/sysemu.h"
Corey Minyard8bfffbc2015-12-17 12:50:05 -060027#include "qemu/timer.h"
28#include "hw/ipmi/ipmi.h"
29#include "qemu/error-report.h"
Markus Armbruster0b8fa322019-05-23 16:35:07 +020030#include "qemu/module.h"
Cédric Le Goater8c6fd7f2017-04-05 14:41:31 +020031#include "hw/loader.h"
Markus Armbrustera27bd6c2019-08-12 07:23:51 +020032#include "hw/qdev-properties.h"
Eduardo Habkostce35e222020-12-11 17:05:12 -050033#include "hw/qdev-properties-system.h"
Markus Armbrusterd6454272019-08-12 07:23:45 +020034#include "migration/vmstate.h"
Corey Minyard8bfffbc2015-12-17 12:50:05 -060035
36#define IPMI_NETFN_CHASSIS 0x00
Corey Minyard8bfffbc2015-12-17 12:50:05 -060037
38#define IPMI_CMD_GET_CHASSIS_CAPABILITIES 0x00
39#define IPMI_CMD_GET_CHASSIS_STATUS 0x01
40#define IPMI_CMD_CHASSIS_CONTROL 0x02
Cédric Le Goaterb7088392016-01-25 15:07:33 +010041#define IPMI_CMD_GET_SYS_RESTART_CAUSE 0x09
Corey Minyard8bfffbc2015-12-17 12:50:05 -060042
43#define IPMI_NETFN_SENSOR_EVENT 0x04
Corey Minyard8bfffbc2015-12-17 12:50:05 -060044
Corey Minyard9380d2e2017-08-18 20:17:48 -050045#define IPMI_CMD_PLATFORM_EVENT_MSG 0x02
Corey Minyard8bfffbc2015-12-17 12:50:05 -060046#define IPMI_CMD_SET_SENSOR_EVT_ENABLE 0x28
47#define IPMI_CMD_GET_SENSOR_EVT_ENABLE 0x29
48#define IPMI_CMD_REARM_SENSOR_EVTS 0x2a
49#define IPMI_CMD_GET_SENSOR_EVT_STATUS 0x2b
50#define IPMI_CMD_GET_SENSOR_READING 0x2d
Cédric Le Goater728710e2016-01-25 15:07:32 +010051#define IPMI_CMD_SET_SENSOR_TYPE 0x2e
52#define IPMI_CMD_GET_SENSOR_TYPE 0x2f
Cédric Le Goatere3f73202019-11-18 10:24:29 +010053#define IPMI_CMD_SET_SENSOR_READING 0x30
Corey Minyard8bfffbc2015-12-17 12:50:05 -060054
55/* #define IPMI_NETFN_APP 0x06 In ipmi.h */
Corey Minyard8bfffbc2015-12-17 12:50:05 -060056
57#define IPMI_CMD_GET_DEVICE_ID 0x01
58#define IPMI_CMD_COLD_RESET 0x02
59#define IPMI_CMD_WARM_RESET 0x03
Cédric Le Goater52ba4d52016-01-25 15:07:34 +010060#define IPMI_CMD_SET_ACPI_POWER_STATE 0x06
61#define IPMI_CMD_GET_ACPI_POWER_STATE 0x07
62#define IPMI_CMD_GET_DEVICE_GUID 0x08
Corey Minyard8bfffbc2015-12-17 12:50:05 -060063#define IPMI_CMD_RESET_WATCHDOG_TIMER 0x22
64#define IPMI_CMD_SET_WATCHDOG_TIMER 0x24
65#define IPMI_CMD_GET_WATCHDOG_TIMER 0x25
66#define IPMI_CMD_SET_BMC_GLOBAL_ENABLES 0x2e
67#define IPMI_CMD_GET_BMC_GLOBAL_ENABLES 0x2f
68#define IPMI_CMD_CLR_MSG_FLAGS 0x30
69#define IPMI_CMD_GET_MSG_FLAGS 0x31
70#define IPMI_CMD_GET_MSG 0x33
71#define IPMI_CMD_SEND_MSG 0x34
72#define IPMI_CMD_READ_EVT_MSG_BUF 0x35
73
74#define IPMI_NETFN_STORAGE 0x0a
Corey Minyard8bfffbc2015-12-17 12:50:05 -060075
76#define IPMI_CMD_GET_SDR_REP_INFO 0x20
77#define IPMI_CMD_GET_SDR_REP_ALLOC_INFO 0x21
78#define IPMI_CMD_RESERVE_SDR_REP 0x22
79#define IPMI_CMD_GET_SDR 0x23
80#define IPMI_CMD_ADD_SDR 0x24
81#define IPMI_CMD_PARTIAL_ADD_SDR 0x25
82#define IPMI_CMD_DELETE_SDR 0x26
83#define IPMI_CMD_CLEAR_SDR_REP 0x27
84#define IPMI_CMD_GET_SDR_REP_TIME 0x28
85#define IPMI_CMD_SET_SDR_REP_TIME 0x29
86#define IPMI_CMD_ENTER_SDR_REP_UPD_MODE 0x2A
87#define IPMI_CMD_EXIT_SDR_REP_UPD_MODE 0x2B
88#define IPMI_CMD_RUN_INIT_AGENT 0x2C
Cédric Le Goater540c07d2017-04-05 14:41:32 +020089#define IPMI_CMD_GET_FRU_AREA_INFO 0x10
90#define IPMI_CMD_READ_FRU_DATA 0x11
91#define IPMI_CMD_WRITE_FRU_DATA 0x12
Corey Minyard8bfffbc2015-12-17 12:50:05 -060092#define IPMI_CMD_GET_SEL_INFO 0x40
93#define IPMI_CMD_GET_SEL_ALLOC_INFO 0x41
94#define IPMI_CMD_RESERVE_SEL 0x42
95#define IPMI_CMD_GET_SEL_ENTRY 0x43
96#define IPMI_CMD_ADD_SEL_ENTRY 0x44
97#define IPMI_CMD_PARTIAL_ADD_SEL_ENTRY 0x45
98#define IPMI_CMD_DELETE_SEL_ENTRY 0x46
99#define IPMI_CMD_CLEAR_SEL 0x47
100#define IPMI_CMD_GET_SEL_TIME 0x48
101#define IPMI_CMD_SET_SEL_TIME 0x49
102
103
104/* Same as a timespec struct. */
105struct ipmi_time {
106 long tv_sec;
107 long tv_nsec;
108};
109
110#define MAX_SEL_SIZE 128
111
112typedef struct IPMISel {
113 uint8_t sel[MAX_SEL_SIZE][16];
114 unsigned int next_free;
115 long time_offset;
116 uint16_t reservation;
117 uint8_t last_addition[4];
118 uint8_t last_clear[4];
119 uint8_t overflow;
120} IPMISel;
121
122#define MAX_SDR_SIZE 16384
123
124typedef struct IPMISdr {
125 uint8_t sdr[MAX_SDR_SIZE];
126 unsigned int next_free;
127 uint16_t next_rec_id;
128 uint16_t reservation;
129 uint8_t last_addition[4];
130 uint8_t last_clear[4];
131 uint8_t overflow;
132} IPMISdr;
133
Cédric Le Goater540c07d2017-04-05 14:41:32 +0200134typedef struct IPMIFru {
135 char *filename;
136 unsigned int nentries;
137 uint16_t areasize;
138 uint8_t *data;
139} IPMIFru;
140
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600141typedef struct IPMISensor {
142 uint8_t status;
143 uint8_t reading;
144 uint16_t states_suppt;
145 uint16_t assert_suppt;
146 uint16_t deassert_suppt;
147 uint16_t states;
148 uint16_t assert_states;
149 uint16_t deassert_states;
150 uint16_t assert_enable;
151 uint16_t deassert_enable;
152 uint8_t sensor_type;
153 uint8_t evt_reading_type_code;
154} IPMISensor;
155#define IPMI_SENSOR_GET_PRESENT(s) ((s)->status & 0x01)
156#define IPMI_SENSOR_SET_PRESENT(s, v) ((s)->status = (s->status & ~0x01) | \
157 !!(v))
158#define IPMI_SENSOR_GET_SCAN_ON(s) ((s)->status & 0x40)
159#define IPMI_SENSOR_SET_SCAN_ON(s, v) ((s)->status = (s->status & ~0x40) | \
160 ((!!(v)) << 6))
161#define IPMI_SENSOR_GET_EVENTS_ON(s) ((s)->status & 0x80)
162#define IPMI_SENSOR_SET_EVENTS_ON(s, v) ((s)->status = (s->status & ~0x80) | \
163 ((!!(v)) << 7))
164#define IPMI_SENSOR_GET_RET_STATUS(s) ((s)->status & 0xc0)
165#define IPMI_SENSOR_SET_RET_STATUS(s, v) ((s)->status = (s->status & ~0xc0) | \
166 (v & 0xc0))
167#define IPMI_SENSOR_IS_DISCRETE(s) ((s)->evt_reading_type_code != 1)
168
169#define MAX_SENSORS 20
170#define IPMI_WATCHDOG_SENSOR 0
171
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600172#define MAX_NETFNS 64
Cédric Le Goater4f298a42016-03-10 15:03:54 +0100173
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600174typedef struct IPMIRcvBufEntry {
175 QTAILQ_ENTRY(IPMIRcvBufEntry) entry;
176 uint8_t len;
177 uint8_t buf[MAX_IPMI_MSG_SIZE];
178} IPMIRcvBufEntry;
179
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600180struct IPMIBmcSim {
181 IPMIBmc parent;
182
183 QEMUTimer *timer;
184
185 uint8_t bmc_global_enables;
186 uint8_t msg_flags;
187
188 bool watchdog_initialized;
189 uint8_t watchdog_use;
190 uint8_t watchdog_action;
191 uint8_t watchdog_pretimeout; /* In seconds */
192 bool watchdog_expired;
193 uint16_t watchdog_timeout; /* in 100's of milliseconds */
194
195 bool watchdog_running;
196 bool watchdog_preaction_ran;
197 int64_t watchdog_expiry;
198
199 uint8_t device_id;
200 uint8_t ipmi_version;
201 uint8_t device_rev;
202 uint8_t fwrev1;
203 uint8_t fwrev2;
Corey Minyard20b23362017-08-28 12:48:44 -0500204 uint32_t mfg_id;
205 uint16_t product_id;
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600206
Cédric Le Goaterb7088392016-01-25 15:07:33 +0100207 uint8_t restart_cause;
208
Cédric Le Goater52ba4d52016-01-25 15:07:34 +0100209 uint8_t acpi_power_state[2];
Corey Minyard7b0cd782017-09-06 15:57:07 -0500210 QemuUUID uuid;
Cédric Le Goater52ba4d52016-01-25 15:07:34 +0100211
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600212 IPMISel sel;
213 IPMISdr sdr;
Cédric Le Goater540c07d2017-04-05 14:41:32 +0200214 IPMIFru fru;
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600215 IPMISensor sensors[MAX_SENSORS];
Cédric Le Goater8c6fd7f2017-04-05 14:41:31 +0200216 char *sdr_filename;
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600217
218 /* Odd netfns are for responses, so we only need the even ones. */
219 const IPMINetfn *netfns[MAX_NETFNS / 2];
220
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600221 /* We allow one event in the buffer */
222 uint8_t evtbuf[16];
223
224 QTAILQ_HEAD(, IPMIRcvBufEntry) rcvbufs;
225};
226
227#define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK (1 << 3)
228#define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL (1 << 1)
229#define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE (1 << 0)
230#define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(s) \
231 (IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK & (s)->msg_flags)
232#define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(s) \
233 (IPMI_BMC_MSG_FLAG_EVT_BUF_FULL & (s)->msg_flags)
234#define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(s) \
235 (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE & (s)->msg_flags)
236
237#define IPMI_BMC_RCV_MSG_QUEUE_INT_BIT 0
238#define IPMI_BMC_EVBUF_FULL_INT_BIT 1
239#define IPMI_BMC_EVENT_MSG_BUF_BIT 2
240#define IPMI_BMC_EVENT_LOG_BIT 3
241#define IPMI_BMC_MSG_INTS_ON(s) ((s)->bmc_global_enables & \
242 (1 << IPMI_BMC_RCV_MSG_QUEUE_INT_BIT))
243#define IPMI_BMC_EVBUF_FULL_INT_ENABLED(s) ((s)->bmc_global_enables & \
244 (1 << IPMI_BMC_EVBUF_FULL_INT_BIT))
245#define IPMI_BMC_EVENT_LOG_ENABLED(s) ((s)->bmc_global_enables & \
246 (1 << IPMI_BMC_EVENT_LOG_BIT))
247#define IPMI_BMC_EVENT_MSG_BUF_ENABLED(s) ((s)->bmc_global_enables & \
248 (1 << IPMI_BMC_EVENT_MSG_BUF_BIT))
249
250#define IPMI_BMC_WATCHDOG_USE_MASK 0xc7
251#define IPMI_BMC_WATCHDOG_ACTION_MASK 0x77
252#define IPMI_BMC_WATCHDOG_GET_USE(s) ((s)->watchdog_use & 0x7)
253#define IPMI_BMC_WATCHDOG_GET_DONT_LOG(s) (((s)->watchdog_use >> 7) & 0x1)
254#define IPMI_BMC_WATCHDOG_GET_DONT_STOP(s) (((s)->watchdog_use >> 6) & 0x1)
255#define IPMI_BMC_WATCHDOG_GET_PRE_ACTION(s) (((s)->watchdog_action >> 4) & 0x7)
256#define IPMI_BMC_WATCHDOG_PRE_NONE 0
257#define IPMI_BMC_WATCHDOG_PRE_SMI 1
258#define IPMI_BMC_WATCHDOG_PRE_NMI 2
259#define IPMI_BMC_WATCHDOG_PRE_MSG_INT 3
260#define IPMI_BMC_WATCHDOG_GET_ACTION(s) ((s)->watchdog_action & 0x7)
261#define IPMI_BMC_WATCHDOG_ACTION_NONE 0
262#define IPMI_BMC_WATCHDOG_ACTION_RESET 1
263#define IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN 2
264#define IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE 3
265
Cédric Le Goatera580d822016-03-10 15:03:55 +0100266#define RSP_BUFFER_INITIALIZER { }
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600267
Cédric Le Goatera580d822016-03-10 15:03:55 +0100268static inline void rsp_buffer_pushmore(RspBuffer *rsp, uint8_t *bytes,
269 unsigned int n)
270{
271 if (rsp->len + n >= sizeof(rsp->buffer)) {
Cédric Le Goater6acb9712016-03-10 15:03:57 +0100272 rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
Cédric Le Goatera580d822016-03-10 15:03:55 +0100273 return;
274 }
275
276 memcpy(&rsp->buffer[rsp->len], bytes, n);
277 rsp->len += n;
278}
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600279
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600280static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs);
281
282static void ipmi_gettime(struct ipmi_time *time)
283{
284 int64_t stime;
285
286 stime = qemu_clock_get_ns(QEMU_CLOCK_HOST);
287 time->tv_sec = stime / 1000000000LL;
288 time->tv_nsec = stime % 1000000000LL;
289}
290
291static int64_t ipmi_getmonotime(void)
292{
293 return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
294}
295
296static void ipmi_timeout(void *opaque)
297{
298 IPMIBmcSim *ibs = opaque;
299
300 ipmi_sim_handle_timeout(ibs);
301}
302
303static void set_timestamp(IPMIBmcSim *ibs, uint8_t *ts)
304{
305 unsigned int val;
306 struct ipmi_time now;
307
308 ipmi_gettime(&now);
309 val = now.tv_sec + ibs->sel.time_offset;
310 ts[0] = val & 0xff;
311 ts[1] = (val >> 8) & 0xff;
312 ts[2] = (val >> 16) & 0xff;
313 ts[3] = (val >> 24) & 0xff;
314}
315
316static void sdr_inc_reservation(IPMISdr *sdr)
317{
318 sdr->reservation++;
319 if (sdr->reservation == 0) {
320 sdr->reservation = 1;
321 }
322}
323
Cédric Le Goatera2295f02016-01-25 15:07:31 +0100324static int sdr_add_entry(IPMIBmcSim *ibs,
325 const struct ipmi_sdr_header *sdrh_entry,
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600326 unsigned int len, uint16_t *recid)
327{
Cédric Le Goatera2295f02016-01-25 15:07:31 +0100328 struct ipmi_sdr_header *sdrh =
329 (struct ipmi_sdr_header *) &ibs->sdr.sdr[ibs->sdr.next_free];
330
331 if ((len < IPMI_SDR_HEADER_SIZE) || (len > 255)) {
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600332 return 1;
333 }
334
Cédric Le Goatera2295f02016-01-25 15:07:31 +0100335 if (ipmi_sdr_length(sdrh_entry) != len) {
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600336 return 1;
337 }
338
339 if (ibs->sdr.next_free + len > MAX_SDR_SIZE) {
340 ibs->sdr.overflow = 1;
341 return 1;
342 }
343
Cédric Le Goatera2295f02016-01-25 15:07:31 +0100344 memcpy(sdrh, sdrh_entry, len);
345 sdrh->rec_id[0] = ibs->sdr.next_rec_id & 0xff;
346 sdrh->rec_id[1] = (ibs->sdr.next_rec_id >> 8) & 0xff;
347 sdrh->sdr_version = 0x51; /* Conform to IPMI 1.5 spec */
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600348
349 if (recid) {
350 *recid = ibs->sdr.next_rec_id;
351 }
352 ibs->sdr.next_rec_id++;
353 set_timestamp(ibs, ibs->sdr.last_addition);
354 ibs->sdr.next_free += len;
355 sdr_inc_reservation(&ibs->sdr);
356 return 0;
357}
358
359static int sdr_find_entry(IPMISdr *sdr, uint16_t recid,
360 unsigned int *retpos, uint16_t *nextrec)
361{
362 unsigned int pos = *retpos;
363
364 while (pos < sdr->next_free) {
Cédric Le Goatera2295f02016-01-25 15:07:31 +0100365 struct ipmi_sdr_header *sdrh =
366 (struct ipmi_sdr_header *) &sdr->sdr[pos];
367 uint16_t trec = ipmi_sdr_recid(sdrh);
368 unsigned int nextpos = pos + ipmi_sdr_length(sdrh);
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600369
370 if (trec == recid) {
371 if (nextrec) {
372 if (nextpos >= sdr->next_free) {
373 *nextrec = 0xffff;
374 } else {
375 *nextrec = (sdr->sdr[nextpos] |
376 (sdr->sdr[nextpos + 1] << 8));
377 }
378 }
379 *retpos = pos;
380 return 0;
381 }
382 pos = nextpos;
383 }
384 return 1;
385}
386
Cédric Le Goater7fabcdb2017-04-05 14:41:33 +0200387int ipmi_bmc_sdr_find(IPMIBmc *b, uint16_t recid,
388 const struct ipmi_sdr_compact **sdr, uint16_t *nextrec)
389
390{
391 IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
392 unsigned int pos;
393
394 pos = 0;
395 if (sdr_find_entry(&ibs->sdr, recid, &pos, nextrec)) {
396 return -1;
397 }
398
399 *sdr = (const struct ipmi_sdr_compact *) &ibs->sdr.sdr[pos];
400 return 0;
401}
402
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600403static void sel_inc_reservation(IPMISel *sel)
404{
405 sel->reservation++;
406 if (sel->reservation == 0) {
407 sel->reservation = 1;
408 }
409}
410
411/* Returns 1 if the SEL is full and can't hold the event. */
412static int sel_add_event(IPMIBmcSim *ibs, uint8_t *event)
413{
Corey Minyard9f7d1d92017-08-18 20:15:02 -0500414 uint8_t ts[4];
415
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600416 event[0] = 0xff;
417 event[1] = 0xff;
Corey Minyard9f7d1d92017-08-18 20:15:02 -0500418 set_timestamp(ibs, ts);
419 if (event[2] < 0xe0) { /* Don't set timestamps for type 0xe0-0xff. */
420 memcpy(event + 3, ts, 4);
421 }
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600422 if (ibs->sel.next_free == MAX_SEL_SIZE) {
423 ibs->sel.overflow = 1;
424 return 1;
425 }
426 event[0] = ibs->sel.next_free & 0xff;
427 event[1] = (ibs->sel.next_free >> 8) & 0xff;
Corey Minyard9f7d1d92017-08-18 20:15:02 -0500428 memcpy(ibs->sel.last_addition, ts, 4);
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600429 memcpy(ibs->sel.sel[ibs->sel.next_free], event, 16);
430 ibs->sel.next_free++;
431 sel_inc_reservation(&ibs->sel);
432 return 0;
433}
434
435static int attn_set(IPMIBmcSim *ibs)
436{
437 return IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs)
438 || IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs)
439 || IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs);
440}
441
442static int attn_irq_enabled(IPMIBmcSim *ibs)
443{
Corey Minyard8bc8af62019-08-16 16:59:07 -0500444 return (IPMI_BMC_MSG_INTS_ON(ibs) &&
445 (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs) ||
446 IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs)))
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600447 || (IPMI_BMC_EVBUF_FULL_INT_ENABLED(ibs) &&
448 IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs));
449}
450
Cédric Le Goatercd60d852017-04-05 14:41:34 +0200451void ipmi_bmc_gen_event(IPMIBmc *b, uint8_t *evt, bool log)
452{
453 IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
454 IPMIInterface *s = ibs->parent.intf;
455 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
456
457 if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) {
458 return;
459 }
460
461 if (log && IPMI_BMC_EVENT_LOG_ENABLED(ibs)) {
462 sel_add_event(ibs, evt);
463 }
464
465 if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) {
466 goto out;
467 }
468
469 memcpy(ibs->evtbuf, evt, 16);
470 ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
471 k->set_atn(s, 1, attn_irq_enabled(ibs));
472 out:
473 return;
474}
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600475static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert,
476 uint8_t evd1, uint8_t evd2, uint8_t evd3)
477{
478 IPMIInterface *s = ibs->parent.intf;
479 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
480 uint8_t evt[16];
481 IPMISensor *sens = ibs->sensors + sens_num;
482
483 if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) {
484 return;
485 }
486 if (!IPMI_SENSOR_GET_EVENTS_ON(sens)) {
487 return;
488 }
489
490 evt[2] = 0x2; /* System event record */
491 evt[7] = ibs->parent.slave_addr;
492 evt[8] = 0;
493 evt[9] = 0x04; /* Format version */
494 evt[10] = sens->sensor_type;
495 evt[11] = sens_num;
496 evt[12] = sens->evt_reading_type_code | (!!deassert << 7);
497 evt[13] = evd1;
498 evt[14] = evd2;
499 evt[15] = evd3;
500
501 if (IPMI_BMC_EVENT_LOG_ENABLED(ibs)) {
502 sel_add_event(ibs, evt);
503 }
504
505 if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) {
Cédric Le Goaterd13ada52016-01-25 15:07:27 +0100506 return;
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600507 }
508
509 memcpy(ibs->evtbuf, evt, 16);
510 ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
511 k->set_atn(s, 1, attn_irq_enabled(ibs));
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600512}
513
514static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor,
515 unsigned int bit, unsigned int val,
516 uint8_t evd1, uint8_t evd2, uint8_t evd3)
517{
518 IPMISensor *sens;
519 uint16_t mask;
520
521 if (sensor >= MAX_SENSORS) {
522 return;
523 }
524 if (bit >= 16) {
525 return;
526 }
527
528 mask = (1 << bit);
529 sens = ibs->sensors + sensor;
530 if (val) {
531 sens->states |= mask & sens->states_suppt;
532 if (sens->assert_states & mask) {
533 return; /* Already asserted */
534 }
535 sens->assert_states |= mask & sens->assert_suppt;
536 if (sens->assert_enable & mask & sens->assert_states) {
537 /* Send an event on assert */
538 gen_event(ibs, sensor, 0, evd1, evd2, evd3);
539 }
540 } else {
541 sens->states &= ~(mask & sens->states_suppt);
542 if (sens->deassert_states & mask) {
543 return; /* Already deasserted */
544 }
545 sens->deassert_states |= mask & sens->deassert_suppt;
546 if (sens->deassert_enable & mask & sens->deassert_states) {
547 /* Send an event on deassert */
548 gen_event(ibs, sensor, 1, evd1, evd2, evd3);
549 }
550 }
551}
552
553static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s)
554{
555 unsigned int i, pos;
556 IPMISensor *sens;
557
558 for (i = 0; i < MAX_SENSORS; i++) {
559 memset(s->sensors + i, 0, sizeof(*sens));
560 }
561
562 pos = 0;
563 for (i = 0; !sdr_find_entry(&s->sdr, i, &pos, NULL); i++) {
Cédric Le Goatera2295f02016-01-25 15:07:31 +0100564 struct ipmi_sdr_compact *sdr =
565 (struct ipmi_sdr_compact *) &s->sdr.sdr[pos];
566 unsigned int len = sdr->header.rec_length;
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600567
568 if (len < 20) {
569 continue;
570 }
Cédric Le Goatera2295f02016-01-25 15:07:31 +0100571 if (sdr->header.rec_type != IPMI_SDR_COMPACT_TYPE) {
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600572 continue; /* Not a sensor SDR we set from */
573 }
574
Cédric Le Goater73d60fa2016-02-16 09:05:44 +0100575 if (sdr->sensor_owner_number >= MAX_SENSORS) {
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600576 continue;
577 }
Cédric Le Goatera2295f02016-01-25 15:07:31 +0100578 sens = s->sensors + sdr->sensor_owner_number;
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600579
580 IPMI_SENSOR_SET_PRESENT(sens, 1);
Cédric Le Goatera2295f02016-01-25 15:07:31 +0100581 IPMI_SENSOR_SET_SCAN_ON(sens, (sdr->sensor_init >> 6) & 1);
582 IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr->sensor_init >> 5) & 1);
583 sens->assert_suppt = sdr->assert_mask[0] | (sdr->assert_mask[1] << 8);
584 sens->deassert_suppt =
585 sdr->deassert_mask[0] | (sdr->deassert_mask[1] << 8);
586 sens->states_suppt =
587 sdr->discrete_mask[0] | (sdr->discrete_mask[1] << 8);
588 sens->sensor_type = sdr->sensor_type;
589 sens->evt_reading_type_code = sdr->reading_type & 0x7f;
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600590
591 /* Enable all the events that are supported. */
592 sens->assert_enable = sens->assert_suppt;
593 sens->deassert_enable = sens->deassert_suppt;
594 }
595}
596
Cédric Le Goatered8da052019-10-28 08:00:26 +0100597int ipmi_sim_register_netfn(IPMIBmcSim *s, unsigned int netfn,
598 const IPMINetfn *netfnd)
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600599{
Corey Minyard93a53642016-01-11 07:32:31 -0600600 if ((netfn & 1) || (netfn >= MAX_NETFNS) || (s->netfns[netfn / 2])) {
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600601 return -1;
602 }
603 s->netfns[netfn / 2] = netfnd;
604 return 0;
605}
606
Cédric Le Goater4f298a42016-03-10 15:03:54 +0100607static const IPMICmdHandler *ipmi_get_handler(IPMIBmcSim *ibs,
608 unsigned int netfn,
609 unsigned int cmd)
610{
611 const IPMICmdHandler *hdl;
612
613 if (netfn & 1 || netfn >= MAX_NETFNS || !ibs->netfns[netfn / 2]) {
614 return NULL;
615 }
616
617 if (cmd >= ibs->netfns[netfn / 2]->cmd_nums) {
618 return NULL;
619 }
620
621 hdl = &ibs->netfns[netfn / 2]->cmd_handlers[cmd];
622 if (!hdl->cmd_handler) {
623 return NULL;
624 }
625
626 return hdl;
627}
628
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600629static void next_timeout(IPMIBmcSim *ibs)
630{
631 int64_t next;
632 if (ibs->watchdog_running) {
633 next = ibs->watchdog_expiry;
634 } else {
635 /* Wait a minute */
636 next = ipmi_getmonotime() + 60 * 1000000000LL;
637 }
638 timer_mod_ns(ibs->timer, next);
639}
640
641static void ipmi_sim_handle_command(IPMIBmc *b,
642 uint8_t *cmd, unsigned int cmd_len,
643 unsigned int max_cmd_len,
644 uint8_t msg_id)
645{
646 IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
647 IPMIInterface *s = ibs->parent.intf;
648 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
Cédric Le Goater4f298a42016-03-10 15:03:54 +0100649 const IPMICmdHandler *hdl;
Cédric Le Goatera580d822016-03-10 15:03:55 +0100650 RspBuffer rsp = RSP_BUFFER_INITIALIZER;
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600651
652 /* Set up the response, set the low bit of NETFN. */
653 /* Note that max_rsp_len must be at least 3 */
Cédric Le Goatera580d822016-03-10 15:03:55 +0100654 if (sizeof(rsp.buffer) < 3) {
Cédric Le Goater6acb9712016-03-10 15:03:57 +0100655 rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
Cédric Le Goaterd13ada52016-01-25 15:07:27 +0100656 goto out;
657 }
658
Cédric Le Goatera580d822016-03-10 15:03:55 +0100659 rsp_buffer_push(&rsp, cmd[0] | 0x04);
660 rsp_buffer_push(&rsp, cmd[1]);
661 rsp_buffer_push(&rsp, 0); /* Assume success */
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600662
663 /* If it's too short or it was truncated, return an error. */
664 if (cmd_len < 2) {
Cédric Le Goater6acb9712016-03-10 15:03:57 +0100665 rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600666 goto out;
667 }
668 if (cmd_len > max_cmd_len) {
Cédric Le Goater6acb9712016-03-10 15:03:57 +0100669 rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600670 goto out;
671 }
672
673 if ((cmd[0] & 0x03) != 0) {
674 /* Only have stuff on LUN 0 */
Cédric Le Goater6acb9712016-03-10 15:03:57 +0100675 rsp_buffer_set_error(&rsp, IPMI_CC_COMMAND_INVALID_FOR_LUN);
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600676 goto out;
677 }
678
Cédric Le Goater4f298a42016-03-10 15:03:54 +0100679 hdl = ipmi_get_handler(ibs, cmd[0] >> 2, cmd[1]);
680 if (!hdl) {
Cédric Le Goater6acb9712016-03-10 15:03:57 +0100681 rsp_buffer_set_error(&rsp, IPMI_CC_INVALID_CMD);
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600682 goto out;
683 }
684
Cédric Le Goater4f298a42016-03-10 15:03:54 +0100685 if (cmd_len < hdl->cmd_len_min) {
Cédric Le Goater6acb9712016-03-10 15:03:57 +0100686 rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
Cédric Le Goater4f298a42016-03-10 15:03:54 +0100687 goto out;
688 }
689
Cédric Le Goatera580d822016-03-10 15:03:55 +0100690 hdl->cmd_handler(ibs, cmd, cmd_len, &rsp);
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600691
692 out:
Cédric Le Goatera580d822016-03-10 15:03:55 +0100693 k->handle_rsp(s, msg_id, rsp.buffer, rsp.len);
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600694
695 next_timeout(ibs);
696}
697
698static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs)
699{
700 IPMIInterface *s = ibs->parent.intf;
701 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
702
703 if (!ibs->watchdog_running) {
704 goto out;
705 }
706
707 if (!ibs->watchdog_preaction_ran) {
708 switch (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs)) {
709 case IPMI_BMC_WATCHDOG_PRE_NMI:
710 ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
711 k->do_hw_op(s, IPMI_SEND_NMI, 0);
712 sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
713 0xc8, (2 << 4) | 0xf, 0xff);
714 break;
715
716 case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
717 ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
718 k->set_atn(s, 1, attn_irq_enabled(ibs));
719 sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
720 0xc8, (3 << 4) | 0xf, 0xff);
721 break;
722
723 default:
724 goto do_full_expiry;
725 }
726
727 ibs->watchdog_preaction_ran = 1;
728 /* Issued the pretimeout, do the rest of the timeout now. */
729 ibs->watchdog_expiry = ipmi_getmonotime();
730 ibs->watchdog_expiry += ibs->watchdog_pretimeout * 1000000000LL;
731 goto out;
732 }
733
734 do_full_expiry:
735 ibs->watchdog_running = 0; /* Stop the watchdog on a timeout */
736 ibs->watchdog_expired |= (1 << IPMI_BMC_WATCHDOG_GET_USE(ibs));
737 switch (IPMI_BMC_WATCHDOG_GET_ACTION(ibs)) {
738 case IPMI_BMC_WATCHDOG_ACTION_NONE:
739 sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 0, 1,
740 0xc0, ibs->watchdog_use & 0xf, 0xff);
741 break;
742
743 case IPMI_BMC_WATCHDOG_ACTION_RESET:
744 sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 1, 1,
745 0xc1, ibs->watchdog_use & 0xf, 0xff);
746 k->do_hw_op(s, IPMI_RESET_CHASSIS, 0);
747 break;
748
749 case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
750 sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
751 0xc2, ibs->watchdog_use & 0xf, 0xff);
752 k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0);
753 break;
754
755 case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
756 sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
757 0xc3, ibs->watchdog_use & 0xf, 0xff);
758 k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0);
759 break;
760 }
761
762 out:
763 next_timeout(ibs);
764}
765
766static void chassis_capabilities(IPMIBmcSim *ibs,
767 uint8_t *cmd, unsigned int cmd_len,
Cédric Le Goatera580d822016-03-10 15:03:55 +0100768 RspBuffer *rsp)
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600769{
Cédric Le Goatera580d822016-03-10 15:03:55 +0100770 rsp_buffer_push(rsp, 0);
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);
774 rsp_buffer_push(rsp, ibs->parent.slave_addr);
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600775}
776
777static void chassis_status(IPMIBmcSim *ibs,
778 uint8_t *cmd, unsigned int cmd_len,
Cédric Le Goatera580d822016-03-10 15:03:55 +0100779 RspBuffer *rsp)
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600780{
Cédric Le Goatera580d822016-03-10 15:03:55 +0100781 rsp_buffer_push(rsp, 0x61); /* Unknown power restore, power is on */
782 rsp_buffer_push(rsp, 0);
783 rsp_buffer_push(rsp, 0);
784 rsp_buffer_push(rsp, 0);
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600785}
786
787static void chassis_control(IPMIBmcSim *ibs,
788 uint8_t *cmd, unsigned int cmd_len,
Cédric Le Goatera580d822016-03-10 15:03:55 +0100789 RspBuffer *rsp)
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600790{
791 IPMIInterface *s = ibs->parent.intf;
792 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
793
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600794 switch (cmd[2] & 0xf) {
795 case 0: /* power down */
Cédric Le Goater6acb9712016-03-10 15:03:57 +0100796 rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0));
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600797 break;
798 case 1: /* power up */
Cédric Le Goater6acb9712016-03-10 15:03:57 +0100799 rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERON_CHASSIS, 0));
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600800 break;
801 case 2: /* power cycle */
Cédric Le Goater6acb9712016-03-10 15:03:57 +0100802 rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0));
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600803 break;
804 case 3: /* hard reset */
Cédric Le Goater6acb9712016-03-10 15:03:57 +0100805 rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 0));
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600806 break;
807 case 4: /* pulse diagnostic interrupt */
Cédric Le Goater6acb9712016-03-10 15:03:57 +0100808 rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_PULSE_DIAG_IRQ, 0));
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600809 break;
810 case 5: /* soft shutdown via ACPI by overtemp emulation */
Cédric Le Goater6acb9712016-03-10 15:03:57 +0100811 rsp_buffer_set_error(rsp, k->do_hw_op(s,
812 IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 0));
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600813 break;
814 default:
Cédric Le Goater6acb9712016-03-10 15:03:57 +0100815 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
Cédric Le Goaterd13ada52016-01-25 15:07:27 +0100816 return;
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600817 }
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600818}
819
Cédric Le Goaterb7088392016-01-25 15:07:33 +0100820static void chassis_get_sys_restart_cause(IPMIBmcSim *ibs,
821 uint8_t *cmd, unsigned int cmd_len,
Cédric Le Goatera580d822016-03-10 15:03:55 +0100822 RspBuffer *rsp)
823
Cédric Le Goaterb7088392016-01-25 15:07:33 +0100824{
Cédric Le Goatera580d822016-03-10 15:03:55 +0100825 rsp_buffer_push(rsp, ibs->restart_cause & 0xf); /* Restart Cause */
826 rsp_buffer_push(rsp, 0); /* Channel 0 */
Cédric Le Goaterb7088392016-01-25 15:07:33 +0100827}
828
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600829static void get_device_id(IPMIBmcSim *ibs,
830 uint8_t *cmd, unsigned int cmd_len,
Cédric Le Goatera580d822016-03-10 15:03:55 +0100831 RspBuffer *rsp)
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600832{
Cédric Le Goatera580d822016-03-10 15:03:55 +0100833 rsp_buffer_push(rsp, ibs->device_id);
834 rsp_buffer_push(rsp, ibs->device_rev & 0xf);
835 rsp_buffer_push(rsp, ibs->fwrev1 & 0x7f);
836 rsp_buffer_push(rsp, ibs->fwrev2);
837 rsp_buffer_push(rsp, ibs->ipmi_version);
838 rsp_buffer_push(rsp, 0x07); /* sensor, SDR, and SEL. */
Corey Minyard20b23362017-08-28 12:48:44 -0500839 rsp_buffer_push(rsp, ibs->mfg_id & 0xff);
840 rsp_buffer_push(rsp, (ibs->mfg_id >> 8) & 0xff);
841 rsp_buffer_push(rsp, (ibs->mfg_id >> 16) & 0xff);
842 rsp_buffer_push(rsp, ibs->product_id & 0xff);
843 rsp_buffer_push(rsp, (ibs->product_id >> 8) & 0xff);
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600844}
845
846static void set_global_enables(IPMIBmcSim *ibs, uint8_t val)
847{
848 IPMIInterface *s = ibs->parent.intf;
849 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
850 bool irqs_on;
851
852 ibs->bmc_global_enables = val;
853
854 irqs_on = val & (IPMI_BMC_EVBUF_FULL_INT_BIT |
855 IPMI_BMC_RCV_MSG_QUEUE_INT_BIT);
856
857 k->set_irq_enable(s, irqs_on);
858}
859
860static void cold_reset(IPMIBmcSim *ibs,
861 uint8_t *cmd, unsigned int cmd_len,
Cédric Le Goatera580d822016-03-10 15:03:55 +0100862 RspBuffer *rsp)
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600863{
864 IPMIInterface *s = ibs->parent.intf;
865 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
866
867 /* Disable all interrupts */
868 set_global_enables(ibs, 1 << IPMI_BMC_EVENT_LOG_BIT);
869
870 if (k->reset) {
871 k->reset(s, true);
872 }
873}
874
875static void warm_reset(IPMIBmcSim *ibs,
876 uint8_t *cmd, unsigned int cmd_len,
Cédric Le Goatera580d822016-03-10 15:03:55 +0100877 RspBuffer *rsp)
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600878{
879 IPMIInterface *s = ibs->parent.intf;
880 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
881
882 if (k->reset) {
883 k->reset(s, false);
884 }
885}
Cédric Le Goater52ba4d52016-01-25 15:07:34 +0100886static void set_acpi_power_state(IPMIBmcSim *ibs,
Cédric Le Goatera580d822016-03-10 15:03:55 +0100887 uint8_t *cmd, unsigned int cmd_len,
888 RspBuffer *rsp)
Cédric Le Goater52ba4d52016-01-25 15:07:34 +0100889{
Cédric Le Goater52ba4d52016-01-25 15:07:34 +0100890 ibs->acpi_power_state[0] = cmd[2];
891 ibs->acpi_power_state[1] = cmd[3];
892}
893
894static void get_acpi_power_state(IPMIBmcSim *ibs,
Cédric Le Goatera580d822016-03-10 15:03:55 +0100895 uint8_t *cmd, unsigned int cmd_len,
896 RspBuffer *rsp)
Cédric Le Goater52ba4d52016-01-25 15:07:34 +0100897{
Cédric Le Goatera580d822016-03-10 15:03:55 +0100898 rsp_buffer_push(rsp, ibs->acpi_power_state[0]);
899 rsp_buffer_push(rsp, ibs->acpi_power_state[1]);
Cédric Le Goater52ba4d52016-01-25 15:07:34 +0100900}
901
902static void get_device_guid(IPMIBmcSim *ibs,
Cédric Le Goatera580d822016-03-10 15:03:55 +0100903 uint8_t *cmd, unsigned int cmd_len,
904 RspBuffer *rsp)
Cédric Le Goater52ba4d52016-01-25 15:07:34 +0100905{
906 unsigned int i;
907
Corey Minyard7b0cd782017-09-06 15:57:07 -0500908 /* An uninitialized uuid is all zeros, use that to know if it is set. */
Cédric Le Goater52ba4d52016-01-25 15:07:34 +0100909 for (i = 0; i < 16; i++) {
Corey Minyard7b0cd782017-09-06 15:57:07 -0500910 if (ibs->uuid.data[i]) {
911 goto uuid_set;
912 }
913 }
914 /* No uuid is set, return an error. */
915 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_CMD);
916 return;
917
918 uuid_set:
919 for (i = 0; i < 16; i++) {
920 rsp_buffer_push(rsp, ibs->uuid.data[i]);
Cédric Le Goater52ba4d52016-01-25 15:07:34 +0100921 }
922}
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600923
924static void set_bmc_global_enables(IPMIBmcSim *ibs,
925 uint8_t *cmd, unsigned int cmd_len,
Cédric Le Goatera580d822016-03-10 15:03:55 +0100926 RspBuffer *rsp)
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600927{
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600928 set_global_enables(ibs, cmd[2]);
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600929}
930
931static void get_bmc_global_enables(IPMIBmcSim *ibs,
932 uint8_t *cmd, unsigned int cmd_len,
Cédric Le Goatera580d822016-03-10 15:03:55 +0100933 RspBuffer *rsp)
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600934{
Cédric Le Goatera580d822016-03-10 15:03:55 +0100935 rsp_buffer_push(rsp, ibs->bmc_global_enables);
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600936}
937
938static void clr_msg_flags(IPMIBmcSim *ibs,
939 uint8_t *cmd, unsigned int cmd_len,
Cédric Le Goatera580d822016-03-10 15:03:55 +0100940 RspBuffer *rsp)
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600941{
942 IPMIInterface *s = ibs->parent.intf;
943 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
944
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600945 ibs->msg_flags &= ~cmd[2];
946 k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600947}
948
949static void get_msg_flags(IPMIBmcSim *ibs,
950 uint8_t *cmd, unsigned int cmd_len,
Cédric Le Goatera580d822016-03-10 15:03:55 +0100951 RspBuffer *rsp)
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600952{
Cédric Le Goatera580d822016-03-10 15:03:55 +0100953 rsp_buffer_push(rsp, ibs->msg_flags);
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600954}
955
956static void read_evt_msg_buf(IPMIBmcSim *ibs,
957 uint8_t *cmd, unsigned int cmd_len,
Cédric Le Goatera580d822016-03-10 15:03:55 +0100958 RspBuffer *rsp)
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600959{
960 IPMIInterface *s = ibs->parent.intf;
961 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
962 unsigned int i;
963
964 if (!(ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL)) {
Cédric Le Goater6acb9712016-03-10 15:03:57 +0100965 rsp_buffer_set_error(rsp, 0x80);
Cédric Le Goaterd13ada52016-01-25 15:07:27 +0100966 return;
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600967 }
968 for (i = 0; i < 16; i++) {
Cédric Le Goatera580d822016-03-10 15:03:55 +0100969 rsp_buffer_push(rsp, ibs->evtbuf[i]);
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600970 }
971 ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
972 k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600973}
974
975static void get_msg(IPMIBmcSim *ibs,
976 uint8_t *cmd, unsigned int cmd_len,
Cédric Le Goatera580d822016-03-10 15:03:55 +0100977 RspBuffer *rsp)
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600978{
979 IPMIRcvBufEntry *msg;
980
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600981 if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
Cédric Le Goater6acb9712016-03-10 15:03:57 +0100982 rsp_buffer_set_error(rsp, 0x80); /* Queue empty */
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600983 goto out;
984 }
Cédric Le Goatera580d822016-03-10 15:03:55 +0100985 rsp_buffer_push(rsp, 0); /* Channel 0 */
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600986 msg = QTAILQ_FIRST(&ibs->rcvbufs);
Cédric Le Goatera580d822016-03-10 15:03:55 +0100987 rsp_buffer_pushmore(rsp, msg->buf, msg->len);
Corey Minyard8bfffbc2015-12-17 12:50:05 -0600988 QTAILQ_REMOVE(&ibs->rcvbufs, msg, entry);
989 g_free(msg);
990
991 if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
992 IPMIInterface *s = ibs->parent.intf;
993 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
994
995 ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
996 k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
997 }
998
Cédric Le Goaterd13ada52016-01-25 15:07:27 +0100999out:
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001000 return;
1001}
1002
1003static unsigned char
1004ipmb_checksum(unsigned char *data, int size, unsigned char csum)
1005{
1006 for (; size > 0; size--, data++) {
1007 csum += *data;
1008 }
1009
1010 return -csum;
1011}
1012
1013static void send_msg(IPMIBmcSim *ibs,
1014 uint8_t *cmd, unsigned int cmd_len,
Cédric Le Goatera580d822016-03-10 15:03:55 +01001015 RspBuffer *rsp)
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001016{
1017 IPMIInterface *s = ibs->parent.intf;
1018 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
1019 IPMIRcvBufEntry *msg;
1020 uint8_t *buf;
1021 uint8_t netfn, rqLun, rsLun, rqSeq;
1022
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001023 if (cmd[2] != 0) {
1024 /* We only handle channel 0 with no options */
Cédric Le Goater6acb9712016-03-10 15:03:57 +01001025 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
Cédric Le Goaterd13ada52016-01-25 15:07:27 +01001026 return;
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001027 }
1028
Cédric Le Goater4f298a42016-03-10 15:03:54 +01001029 if (cmd_len < 10) {
Cédric Le Goater6acb9712016-03-10 15:03:57 +01001030 rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
Cédric Le Goater4f298a42016-03-10 15:03:54 +01001031 return;
1032 }
1033
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001034 if (cmd[3] != 0x40) {
1035 /* We only emulate a MC at address 0x40. */
Cédric Le Goater6acb9712016-03-10 15:03:57 +01001036 rsp_buffer_set_error(rsp, 0x83); /* NAK on write */
Cédric Le Goaterd13ada52016-01-25 15:07:27 +01001037 return;
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001038 }
1039
1040 cmd += 3; /* Skip the header. */
1041 cmd_len -= 3;
1042
1043 /*
1044 * At this point we "send" the message successfully. Any error will
1045 * be returned in the response.
1046 */
1047 if (ipmb_checksum(cmd, cmd_len, 0) != 0 ||
1048 cmd[3] != 0x20) { /* Improper response address */
Cédric Le Goaterd13ada52016-01-25 15:07:27 +01001049 return; /* No response */
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001050 }
1051
1052 netfn = cmd[1] >> 2;
1053 rqLun = cmd[4] & 0x3;
1054 rsLun = cmd[1] & 0x3;
1055 rqSeq = cmd[4] >> 2;
1056
1057 if (rqLun != 2) {
1058 /* We only support LUN 2 coming back to us. */
Cédric Le Goaterd13ada52016-01-25 15:07:27 +01001059 return;
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001060 }
1061
1062 msg = g_malloc(sizeof(*msg));
1063 msg->buf[0] = ((netfn | 1) << 2) | rqLun; /* NetFN, and make a response */
1064 msg->buf[1] = ipmb_checksum(msg->buf, 1, 0);
1065 msg->buf[2] = cmd[0]; /* rsSA */
1066 msg->buf[3] = (rqSeq << 2) | rsLun;
1067 msg->buf[4] = cmd[5]; /* Cmd */
1068 msg->buf[5] = 0; /* Completion Code */
1069 msg->len = 6;
1070
1071 if ((cmd[1] >> 2) != IPMI_NETFN_APP || cmd[5] != IPMI_CMD_GET_DEVICE_ID) {
1072 /* Not a command we handle. */
1073 msg->buf[5] = IPMI_CC_INVALID_CMD;
1074 goto end_msg;
1075 }
1076
1077 buf = msg->buf + msg->len; /* After the CC */
1078 buf[0] = 0;
1079 buf[1] = 0;
1080 buf[2] = 0;
1081 buf[3] = 0;
1082 buf[4] = 0x51;
1083 buf[5] = 0;
1084 buf[6] = 0;
1085 buf[7] = 0;
1086 buf[8] = 0;
1087 buf[9] = 0;
1088 buf[10] = 0;
1089 msg->len += 11;
1090
1091 end_msg:
1092 msg->buf[msg->len] = ipmb_checksum(msg->buf, msg->len, 0);
1093 msg->len++;
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001094 QTAILQ_INSERT_TAIL(&ibs->rcvbufs, msg, entry);
1095 ibs->msg_flags |= IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
1096 k->set_atn(s, 1, attn_irq_enabled(ibs));
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001097}
1098
1099static void do_watchdog_reset(IPMIBmcSim *ibs)
1100{
1101 if (IPMI_BMC_WATCHDOG_GET_ACTION(ibs) ==
1102 IPMI_BMC_WATCHDOG_ACTION_NONE) {
1103 ibs->watchdog_running = 0;
1104 return;
1105 }
1106 ibs->watchdog_preaction_ran = 0;
1107
1108
1109 /* Timeout is in tenths of a second, offset is in seconds */
1110 ibs->watchdog_expiry = ipmi_getmonotime();
1111 ibs->watchdog_expiry += ibs->watchdog_timeout * 100000000LL;
1112 if (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs) != IPMI_BMC_WATCHDOG_PRE_NONE) {
1113 ibs->watchdog_expiry -= ibs->watchdog_pretimeout * 1000000000LL;
1114 }
1115 ibs->watchdog_running = 1;
1116}
1117
1118static void reset_watchdog_timer(IPMIBmcSim *ibs,
1119 uint8_t *cmd, unsigned int cmd_len,
Cédric Le Goatera580d822016-03-10 15:03:55 +01001120 RspBuffer *rsp)
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001121{
1122 if (!ibs->watchdog_initialized) {
Cédric Le Goater6acb9712016-03-10 15:03:57 +01001123 rsp_buffer_set_error(rsp, 0x80);
Cédric Le Goaterd13ada52016-01-25 15:07:27 +01001124 return;
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001125 }
1126 do_watchdog_reset(ibs);
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001127}
1128
1129static void set_watchdog_timer(IPMIBmcSim *ibs,
1130 uint8_t *cmd, unsigned int cmd_len,
Cédric Le Goatera580d822016-03-10 15:03:55 +01001131 RspBuffer *rsp)
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001132{
1133 IPMIInterface *s = ibs->parent.intf;
1134 IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
1135 unsigned int val;
1136
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001137 val = cmd[2] & 0x7; /* Validate use */
1138 if (val == 0 || val > 5) {
Cédric Le Goater6acb9712016-03-10 15:03:57 +01001139 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
Cédric Le Goaterd13ada52016-01-25 15:07:27 +01001140 return;
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001141 }
1142 val = cmd[3] & 0x7; /* Validate action */
1143 switch (val) {
1144 case IPMI_BMC_WATCHDOG_ACTION_NONE:
1145 break;
1146
1147 case IPMI_BMC_WATCHDOG_ACTION_RESET:
Cédric Le Goater6acb9712016-03-10 15:03:57 +01001148 rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 1));
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001149 break;
1150
1151 case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
Cédric Le Goater6acb9712016-03-10 15:03:57 +01001152 rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 1));
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001153 break;
1154
1155 case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
Cédric Le Goater6acb9712016-03-10 15:03:57 +01001156 rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 1));
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001157 break;
1158
1159 default:
Cédric Le Goater6acb9712016-03-10 15:03:57 +01001160 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001161 }
Cédric Le Goatera580d822016-03-10 15:03:55 +01001162 if (rsp->buffer[2]) {
Cédric Le Goater6acb9712016-03-10 15:03:57 +01001163 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
Cédric Le Goaterd13ada52016-01-25 15:07:27 +01001164 return;
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001165 }
1166
1167 val = (cmd[3] >> 4) & 0x7; /* Validate preaction */
1168 switch (val) {
1169 case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
1170 case IPMI_BMC_WATCHDOG_PRE_NONE:
1171 break;
1172
1173 case IPMI_BMC_WATCHDOG_PRE_NMI:
Corey Minyard6af94762019-08-16 09:09:21 -05001174 if (k->do_hw_op(s, IPMI_SEND_NMI, 1)) {
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001175 /* NMI not supported. */
Cédric Le Goater6acb9712016-03-10 15:03:57 +01001176 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
Cédric Le Goaterd13ada52016-01-25 15:07:27 +01001177 return;
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001178 }
Corey Minyard37eebb82016-01-11 07:32:32 -06001179 break;
1180
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001181 default:
1182 /* We don't support PRE_SMI */
Cédric Le Goater6acb9712016-03-10 15:03:57 +01001183 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
Cédric Le Goaterd13ada52016-01-25 15:07:27 +01001184 return;
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001185 }
1186
1187 ibs->watchdog_initialized = 1;
1188 ibs->watchdog_use = cmd[2] & IPMI_BMC_WATCHDOG_USE_MASK;
1189 ibs->watchdog_action = cmd[3] & IPMI_BMC_WATCHDOG_ACTION_MASK;
1190 ibs->watchdog_pretimeout = cmd[4];
1191 ibs->watchdog_expired &= ~cmd[5];
1192 ibs->watchdog_timeout = cmd[6] | (((uint16_t) cmd[7]) << 8);
1193 if (ibs->watchdog_running & IPMI_BMC_WATCHDOG_GET_DONT_STOP(ibs)) {
1194 do_watchdog_reset(ibs);
1195 } else {
1196 ibs->watchdog_running = 0;
1197 }
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001198}
1199
1200static void get_watchdog_timer(IPMIBmcSim *ibs,
1201 uint8_t *cmd, unsigned int cmd_len,
Cédric Le Goatera580d822016-03-10 15:03:55 +01001202 RspBuffer *rsp)
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001203{
Cédric Le Goatera580d822016-03-10 15:03:55 +01001204 rsp_buffer_push(rsp, ibs->watchdog_use);
1205 rsp_buffer_push(rsp, ibs->watchdog_action);
1206 rsp_buffer_push(rsp, ibs->watchdog_pretimeout);
1207 rsp_buffer_push(rsp, ibs->watchdog_expired);
Corey Minyardfb457702019-08-16 13:31:46 -05001208 rsp_buffer_push(rsp, ibs->watchdog_timeout & 0xff);
1209 rsp_buffer_push(rsp, (ibs->watchdog_timeout >> 8) & 0xff);
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001210 if (ibs->watchdog_running) {
1211 long timeout;
1212 timeout = ((ibs->watchdog_expiry - ipmi_getmonotime() + 50000000)
1213 / 100000000);
Cédric Le Goatera580d822016-03-10 15:03:55 +01001214 rsp_buffer_push(rsp, timeout & 0xff);
1215 rsp_buffer_push(rsp, (timeout >> 8) & 0xff);
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001216 } else {
Cédric Le Goatera580d822016-03-10 15:03:55 +01001217 rsp_buffer_push(rsp, 0);
1218 rsp_buffer_push(rsp, 0);
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001219 }
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001220}
1221
1222static void get_sdr_rep_info(IPMIBmcSim *ibs,
1223 uint8_t *cmd, unsigned int cmd_len,
Cédric Le Goatera580d822016-03-10 15:03:55 +01001224 RspBuffer *rsp)
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001225{
1226 unsigned int i;
1227
Cédric Le Goatera580d822016-03-10 15:03:55 +01001228 rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 spec */
1229 rsp_buffer_push(rsp, ibs->sdr.next_rec_id & 0xff);
1230 rsp_buffer_push(rsp, (ibs->sdr.next_rec_id >> 8) & 0xff);
1231 rsp_buffer_push(rsp, (MAX_SDR_SIZE - ibs->sdr.next_free) & 0xff);
1232 rsp_buffer_push(rsp, ((MAX_SDR_SIZE - ibs->sdr.next_free) >> 8) & 0xff);
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001233 for (i = 0; i < 4; i++) {
Cédric Le Goatera580d822016-03-10 15:03:55 +01001234 rsp_buffer_push(rsp, ibs->sdr.last_addition[i]);
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001235 }
1236 for (i = 0; i < 4; i++) {
Cédric Le Goatera580d822016-03-10 15:03:55 +01001237 rsp_buffer_push(rsp, ibs->sdr.last_clear[i]);
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001238 }
1239 /* Only modal support, reserve supported */
Cédric Le Goatera580d822016-03-10 15:03:55 +01001240 rsp_buffer_push(rsp, (ibs->sdr.overflow << 7) | 0x22);
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001241}
1242
1243static void reserve_sdr_rep(IPMIBmcSim *ibs,
1244 uint8_t *cmd, unsigned int cmd_len,
Cédric Le Goatera580d822016-03-10 15:03:55 +01001245 RspBuffer *rsp)
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001246{
Cédric Le Goatera580d822016-03-10 15:03:55 +01001247 rsp_buffer_push(rsp, ibs->sdr.reservation & 0xff);
1248 rsp_buffer_push(rsp, (ibs->sdr.reservation >> 8) & 0xff);
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001249}
1250
1251static void get_sdr(IPMIBmcSim *ibs,
1252 uint8_t *cmd, unsigned int cmd_len,
Cédric Le Goatera580d822016-03-10 15:03:55 +01001253 RspBuffer *rsp)
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001254{
1255 unsigned int pos;
1256 uint16_t nextrec;
Cédric Le Goatera2295f02016-01-25 15:07:31 +01001257 struct ipmi_sdr_header *sdrh;
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001258
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001259 if (cmd[6]) {
Cédric Le Goater7f996412016-03-10 15:03:56 +01001260 if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) {
Cédric Le Goater6acb9712016-03-10 15:03:57 +01001261 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
Cédric Le Goater7f996412016-03-10 15:03:56 +01001262 return;
1263 }
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001264 }
Cédric Le Goater7f996412016-03-10 15:03:56 +01001265
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001266 pos = 0;
1267 if (sdr_find_entry(&ibs->sdr, cmd[4] | (cmd[5] << 8),
1268 &pos, &nextrec)) {
Cédric Le Goater6acb9712016-03-10 15:03:57 +01001269 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
Cédric Le Goaterd13ada52016-01-25 15:07:27 +01001270 return;
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001271 }
Cédric Le Goatera2295f02016-01-25 15:07:31 +01001272
1273 sdrh = (struct ipmi_sdr_header *) &ibs->sdr.sdr[pos];
1274
1275 if (cmd[6] > ipmi_sdr_length(sdrh)) {
Cédric Le Goater6acb9712016-03-10 15:03:57 +01001276 rsp_buffer_set_error(rsp, IPMI_CC_PARM_OUT_OF_RANGE);
Cédric Le Goaterd13ada52016-01-25 15:07:27 +01001277 return;
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001278 }
1279
Cédric Le Goatera580d822016-03-10 15:03:55 +01001280 rsp_buffer_push(rsp, nextrec & 0xff);
1281 rsp_buffer_push(rsp, (nextrec >> 8) & 0xff);
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001282
1283 if (cmd[7] == 0xff) {
Cédric Le Goatera2295f02016-01-25 15:07:31 +01001284 cmd[7] = ipmi_sdr_length(sdrh) - cmd[6];
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001285 }
1286
Cédric Le Goatera580d822016-03-10 15:03:55 +01001287 if ((cmd[7] + rsp->len) > sizeof(rsp->buffer)) {
Cédric Le Goater6acb9712016-03-10 15:03:57 +01001288 rsp_buffer_set_error(rsp, IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES);
Cédric Le Goaterd13ada52016-01-25 15:07:27 +01001289 return;
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001290 }
Cédric Le Goatera580d822016-03-10 15:03:55 +01001291
1292 rsp_buffer_pushmore(rsp, ibs->sdr.sdr + pos + cmd[6], cmd[7]);
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001293}
1294
1295static void add_sdr(IPMIBmcSim *ibs,
1296 uint8_t *cmd, unsigned int cmd_len,
Cédric Le Goatera580d822016-03-10 15:03:55 +01001297 RspBuffer *rsp)
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001298{
1299 uint16_t recid;
Cédric Le Goatera2295f02016-01-25 15:07:31 +01001300 struct ipmi_sdr_header *sdrh = (struct ipmi_sdr_header *) cmd + 2;
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001301
Cédric Le Goatera2295f02016-01-25 15:07:31 +01001302 if (sdr_add_entry(ibs, sdrh, cmd_len - 2, &recid)) {
Cédric Le Goater6acb9712016-03-10 15:03:57 +01001303 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
Cédric Le Goaterd13ada52016-01-25 15:07:27 +01001304 return;
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001305 }
Cédric Le Goatera580d822016-03-10 15:03:55 +01001306 rsp_buffer_push(rsp, recid & 0xff);
1307 rsp_buffer_push(rsp, (recid >> 8) & 0xff);
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001308}
1309
1310static void clear_sdr_rep(IPMIBmcSim *ibs,
1311 uint8_t *cmd, unsigned int cmd_len,
Cédric Le Goatera580d822016-03-10 15:03:55 +01001312 RspBuffer *rsp)
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001313{
Cédric Le Goater7f996412016-03-10 15:03:56 +01001314 if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) {
Cédric Le Goater6acb9712016-03-10 15:03:57 +01001315 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
Cédric Le Goater7f996412016-03-10 15:03:56 +01001316 return;
1317 }
1318
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001319 if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
Cédric Le Goater6acb9712016-03-10 15:03:57 +01001320 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
Cédric Le Goaterd13ada52016-01-25 15:07:27 +01001321 return;
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001322 }
1323 if (cmd[7] == 0xaa) {
1324 ibs->sdr.next_free = 0;
1325 ibs->sdr.overflow = 0;
1326 set_timestamp(ibs, ibs->sdr.last_clear);
Cédric Le Goatera580d822016-03-10 15:03:55 +01001327 rsp_buffer_push(rsp, 1); /* Erasure complete */
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001328 sdr_inc_reservation(&ibs->sdr);
1329 } else if (cmd[7] == 0) {
Cédric Le Goatera580d822016-03-10 15:03:55 +01001330 rsp_buffer_push(rsp, 1); /* Erasure complete */
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001331 } else {
Cédric Le Goater6acb9712016-03-10 15:03:57 +01001332 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
Cédric Le Goaterd13ada52016-01-25 15:07:27 +01001333 return;
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001334 }
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001335}
1336
1337static void get_sel_info(IPMIBmcSim *ibs,
1338 uint8_t *cmd, unsigned int cmd_len,
Cédric Le Goatera580d822016-03-10 15:03:55 +01001339 RspBuffer *rsp)
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001340{
1341 unsigned int i, val;
1342
Cédric Le Goatera580d822016-03-10 15:03:55 +01001343 rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 */
1344 rsp_buffer_push(rsp, ibs->sel.next_free & 0xff);
1345 rsp_buffer_push(rsp, (ibs->sel.next_free >> 8) & 0xff);
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001346 val = (MAX_SEL_SIZE - ibs->sel.next_free) * 16;
Cédric Le Goatera580d822016-03-10 15:03:55 +01001347 rsp_buffer_push(rsp, val & 0xff);
1348 rsp_buffer_push(rsp, (val >> 8) & 0xff);
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001349 for (i = 0; i < 4; i++) {
Cédric Le Goatera580d822016-03-10 15:03:55 +01001350 rsp_buffer_push(rsp, ibs->sel.last_addition[i]);
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001351 }
1352 for (i = 0; i < 4; i++) {
Cédric Le Goatera580d822016-03-10 15:03:55 +01001353 rsp_buffer_push(rsp, ibs->sel.last_clear[i]);
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001354 }
1355 /* Only support Reserve SEL */
Cédric Le Goatera580d822016-03-10 15:03:55 +01001356 rsp_buffer_push(rsp, (ibs->sel.overflow << 7) | 0x02);
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001357}
1358
Cédric Le Goater540c07d2017-04-05 14:41:32 +02001359static void get_fru_area_info(IPMIBmcSim *ibs,
1360 uint8_t *cmd, unsigned int cmd_len,
1361 RspBuffer *rsp)
1362{
1363 uint8_t fruid;
1364 uint16_t fru_entry_size;
1365
1366 fruid = cmd[2];
1367
1368 if (fruid >= ibs->fru.nentries) {
1369 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1370 return;
1371 }
1372
1373 fru_entry_size = ibs->fru.areasize;
1374
1375 rsp_buffer_push(rsp, fru_entry_size & 0xff);
1376 rsp_buffer_push(rsp, fru_entry_size >> 8 & 0xff);
1377 rsp_buffer_push(rsp, 0x0);
1378}
1379
1380static void read_fru_data(IPMIBmcSim *ibs,
1381 uint8_t *cmd, unsigned int cmd_len,
1382 RspBuffer *rsp)
1383{
1384 uint8_t fruid;
1385 uint16_t offset;
1386 int i;
1387 uint8_t *fru_entry;
1388 unsigned int count;
1389
1390 fruid = cmd[2];
1391 offset = (cmd[3] | cmd[4] << 8);
1392
1393 if (fruid >= ibs->fru.nentries) {
1394 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1395 return;
1396 }
1397
1398 if (offset >= ibs->fru.areasize - 1) {
1399 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1400 return;
1401 }
1402
1403 fru_entry = &ibs->fru.data[fruid * ibs->fru.areasize];
1404
1405 count = MIN(cmd[5], ibs->fru.areasize - offset);
1406
1407 rsp_buffer_push(rsp, count & 0xff);
1408 for (i = 0; i < count; i++) {
1409 rsp_buffer_push(rsp, fru_entry[offset + i]);
1410 }
1411}
1412
1413static void write_fru_data(IPMIBmcSim *ibs,
1414 uint8_t *cmd, unsigned int cmd_len,
1415 RspBuffer *rsp)
1416{
1417 uint8_t fruid;
1418 uint16_t offset;
1419 uint8_t *fru_entry;
1420 unsigned int count;
1421
1422 fruid = cmd[2];
1423 offset = (cmd[3] | cmd[4] << 8);
1424
1425 if (fruid >= ibs->fru.nentries) {
1426 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1427 return;
1428 }
1429
1430 if (offset >= ibs->fru.areasize - 1) {
1431 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1432 return;
1433 }
1434
1435 fru_entry = &ibs->fru.data[fruid * ibs->fru.areasize];
1436
1437 count = MIN(cmd_len - 5, ibs->fru.areasize - offset);
1438
1439 memcpy(fru_entry + offset, cmd + 5, count);
1440
1441 rsp_buffer_push(rsp, count & 0xff);
1442}
1443
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001444static void reserve_sel(IPMIBmcSim *ibs,
1445 uint8_t *cmd, unsigned int cmd_len,
Cédric Le Goatera580d822016-03-10 15:03:55 +01001446 RspBuffer *rsp)
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001447{
Cédric Le Goatera580d822016-03-10 15:03:55 +01001448 rsp_buffer_push(rsp, ibs->sel.reservation & 0xff);
1449 rsp_buffer_push(rsp, (ibs->sel.reservation >> 8) & 0xff);
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001450}
1451
1452static void get_sel_entry(IPMIBmcSim *ibs,
1453 uint8_t *cmd, unsigned int cmd_len,
Cédric Le Goatera580d822016-03-10 15:03:55 +01001454 RspBuffer *rsp)
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001455{
1456 unsigned int val;
1457
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001458 if (cmd[6]) {
Cédric Le Goater7f996412016-03-10 15:03:56 +01001459 if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) {
Cédric Le Goater6acb9712016-03-10 15:03:57 +01001460 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
Cédric Le Goater7f996412016-03-10 15:03:56 +01001461 return;
1462 }
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001463 }
1464 if (ibs->sel.next_free == 0) {
Cédric Le Goater6acb9712016-03-10 15:03:57 +01001465 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
Cédric Le Goaterd13ada52016-01-25 15:07:27 +01001466 return;
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001467 }
1468 if (cmd[6] > 15) {
Cédric Le Goater6acb9712016-03-10 15:03:57 +01001469 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
Cédric Le Goaterd13ada52016-01-25 15:07:27 +01001470 return;
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001471 }
1472 if (cmd[7] == 0xff) {
1473 cmd[7] = 16;
1474 } else if ((cmd[7] + cmd[6]) > 16) {
Cédric Le Goater6acb9712016-03-10 15:03:57 +01001475 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
Cédric Le Goaterd13ada52016-01-25 15:07:27 +01001476 return;
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001477 } else {
1478 cmd[7] += cmd[6];
1479 }
1480
1481 val = cmd[4] | (cmd[5] << 8);
1482 if (val == 0xffff) {
1483 val = ibs->sel.next_free - 1;
1484 } else if (val >= ibs->sel.next_free) {
Cédric Le Goater6acb9712016-03-10 15:03:57 +01001485 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
Cédric Le Goaterd13ada52016-01-25 15:07:27 +01001486 return;
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001487 }
1488 if ((val + 1) == ibs->sel.next_free) {
Cédric Le Goatera580d822016-03-10 15:03:55 +01001489 rsp_buffer_push(rsp, 0xff);
1490 rsp_buffer_push(rsp, 0xff);
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001491 } else {
Cédric Le Goatera580d822016-03-10 15:03:55 +01001492 rsp_buffer_push(rsp, (val + 1) & 0xff);
1493 rsp_buffer_push(rsp, ((val + 1) >> 8) & 0xff);
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001494 }
1495 for (; cmd[6] < cmd[7]; cmd[6]++) {
Cédric Le Goatera580d822016-03-10 15:03:55 +01001496 rsp_buffer_push(rsp, ibs->sel.sel[val][cmd[6]]);
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001497 }
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001498}
1499
1500static void add_sel_entry(IPMIBmcSim *ibs,
1501 uint8_t *cmd, unsigned int cmd_len,
Cédric Le Goatera580d822016-03-10 15:03:55 +01001502 RspBuffer *rsp)
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001503{
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001504 if (sel_add_event(ibs, cmd + 2)) {
Cédric Le Goater6acb9712016-03-10 15:03:57 +01001505 rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE);
Cédric Le Goaterd13ada52016-01-25 15:07:27 +01001506 return;
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001507 }
1508 /* sel_add_event fills in the record number. */
Cédric Le Goatera580d822016-03-10 15:03:55 +01001509 rsp_buffer_push(rsp, cmd[2]);
1510 rsp_buffer_push(rsp, cmd[3]);
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001511}
1512
1513static void clear_sel(IPMIBmcSim *ibs,
1514 uint8_t *cmd, unsigned int cmd_len,
Cédric Le Goatera580d822016-03-10 15:03:55 +01001515 RspBuffer *rsp)
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001516{
Cédric Le Goater7f996412016-03-10 15:03:56 +01001517 if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) {
Cédric Le Goater6acb9712016-03-10 15:03:57 +01001518 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
Cédric Le Goater7f996412016-03-10 15:03:56 +01001519 return;
1520 }
1521
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001522 if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
Cédric Le Goater6acb9712016-03-10 15:03:57 +01001523 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
Cédric Le Goaterd13ada52016-01-25 15:07:27 +01001524 return;
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001525 }
1526 if (cmd[7] == 0xaa) {
1527 ibs->sel.next_free = 0;
1528 ibs->sel.overflow = 0;
1529 set_timestamp(ibs, ibs->sdr.last_clear);
Cédric Le Goatera580d822016-03-10 15:03:55 +01001530 rsp_buffer_push(rsp, 1); /* Erasure complete */
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001531 sel_inc_reservation(&ibs->sel);
1532 } else if (cmd[7] == 0) {
Cédric Le Goatera580d822016-03-10 15:03:55 +01001533 rsp_buffer_push(rsp, 1); /* Erasure complete */
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001534 } else {
Cédric Le Goater6acb9712016-03-10 15:03:57 +01001535 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
Cédric Le Goaterd13ada52016-01-25 15:07:27 +01001536 return;
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001537 }
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001538}
1539
1540static void get_sel_time(IPMIBmcSim *ibs,
1541 uint8_t *cmd, unsigned int cmd_len,
Cédric Le Goatera580d822016-03-10 15:03:55 +01001542 RspBuffer *rsp)
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001543{
1544 uint32_t val;
1545 struct ipmi_time now;
1546
1547 ipmi_gettime(&now);
1548 val = now.tv_sec + ibs->sel.time_offset;
Cédric Le Goatera580d822016-03-10 15:03:55 +01001549 rsp_buffer_push(rsp, val & 0xff);
1550 rsp_buffer_push(rsp, (val >> 8) & 0xff);
1551 rsp_buffer_push(rsp, (val >> 16) & 0xff);
1552 rsp_buffer_push(rsp, (val >> 24) & 0xff);
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001553}
1554
1555static void set_sel_time(IPMIBmcSim *ibs,
1556 uint8_t *cmd, unsigned int cmd_len,
Cédric Le Goatera580d822016-03-10 15:03:55 +01001557 RspBuffer *rsp)
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001558{
1559 uint32_t val;
1560 struct ipmi_time now;
1561
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001562 val = cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24);
1563 ipmi_gettime(&now);
1564 ibs->sel.time_offset = now.tv_sec - ((long) val);
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001565}
1566
Corey Minyard9380d2e2017-08-18 20:17:48 -05001567static void platform_event_msg(IPMIBmcSim *ibs,
1568 uint8_t *cmd, unsigned int cmd_len,
1569 RspBuffer *rsp)
1570{
1571 uint8_t event[16];
1572
1573 event[2] = 2; /* System event record */
1574 event[7] = cmd[2]; /* Generator ID */
1575 event[8] = 0;
1576 event[9] = cmd[3]; /* EvMRev */
1577 event[10] = cmd[4]; /* Sensor type */
1578 event[11] = cmd[5]; /* Sensor number */
1579 event[12] = cmd[6]; /* Event dir / Event type */
1580 event[13] = cmd[7]; /* Event data 1 */
1581 event[14] = cmd[8]; /* Event data 2 */
1582 event[15] = cmd[9]; /* Event data 3 */
1583
1584 if (sel_add_event(ibs, event)) {
1585 rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE);
1586 }
1587}
1588
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001589static void set_sensor_evt_enable(IPMIBmcSim *ibs,
1590 uint8_t *cmd, unsigned int cmd_len,
Cédric Le Goatera580d822016-03-10 15:03:55 +01001591 RspBuffer *rsp)
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001592{
1593 IPMISensor *sens;
1594
Cédric Le Goater73d60fa2016-02-16 09:05:44 +01001595 if ((cmd[2] >= MAX_SENSORS) ||
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001596 !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
Cédric Le Goater6acb9712016-03-10 15:03:57 +01001597 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
Cédric Le Goaterd13ada52016-01-25 15:07:27 +01001598 return;
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001599 }
1600 sens = ibs->sensors + cmd[2];
1601 switch ((cmd[3] >> 4) & 0x3) {
1602 case 0: /* Do not change */
1603 break;
1604 case 1: /* Enable bits */
1605 if (cmd_len > 4) {
1606 sens->assert_enable |= cmd[4];
1607 }
1608 if (cmd_len > 5) {
1609 sens->assert_enable |= cmd[5] << 8;
1610 }
1611 if (cmd_len > 6) {
1612 sens->deassert_enable |= cmd[6];
1613 }
1614 if (cmd_len > 7) {
1615 sens->deassert_enable |= cmd[7] << 8;
1616 }
1617 break;
1618 case 2: /* Disable bits */
1619 if (cmd_len > 4) {
1620 sens->assert_enable &= ~cmd[4];
1621 }
1622 if (cmd_len > 5) {
1623 sens->assert_enable &= ~(cmd[5] << 8);
1624 }
1625 if (cmd_len > 6) {
1626 sens->deassert_enable &= ~cmd[6];
1627 }
1628 if (cmd_len > 7) {
1629 sens->deassert_enable &= ~(cmd[7] << 8);
1630 }
1631 break;
1632 case 3:
Cédric Le Goater6acb9712016-03-10 15:03:57 +01001633 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
Cédric Le Goaterd13ada52016-01-25 15:07:27 +01001634 return;
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001635 }
1636 IPMI_SENSOR_SET_RET_STATUS(sens, cmd[3]);
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001637}
1638
1639static void get_sensor_evt_enable(IPMIBmcSim *ibs,
1640 uint8_t *cmd, unsigned int cmd_len,
Cédric Le Goatera580d822016-03-10 15:03:55 +01001641 RspBuffer *rsp)
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001642{
1643 IPMISensor *sens;
1644
Cédric Le Goater73d60fa2016-02-16 09:05:44 +01001645 if ((cmd[2] >= MAX_SENSORS) ||
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001646 !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
Cédric Le Goater6acb9712016-03-10 15:03:57 +01001647 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
Cédric Le Goaterd13ada52016-01-25 15:07:27 +01001648 return;
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001649 }
1650 sens = ibs->sensors + cmd[2];
Cédric Le Goatera580d822016-03-10 15:03:55 +01001651 rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1652 rsp_buffer_push(rsp, sens->assert_enable & 0xff);
1653 rsp_buffer_push(rsp, (sens->assert_enable >> 8) & 0xff);
1654 rsp_buffer_push(rsp, sens->deassert_enable & 0xff);
1655 rsp_buffer_push(rsp, (sens->deassert_enable >> 8) & 0xff);
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001656}
1657
1658static void rearm_sensor_evts(IPMIBmcSim *ibs,
1659 uint8_t *cmd, unsigned int cmd_len,
Cédric Le Goatera580d822016-03-10 15:03:55 +01001660 RspBuffer *rsp)
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001661{
1662 IPMISensor *sens;
1663
Cédric Le Goater73d60fa2016-02-16 09:05:44 +01001664 if ((cmd[2] >= MAX_SENSORS) ||
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001665 !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
Cédric Le Goater6acb9712016-03-10 15:03:57 +01001666 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
Cédric Le Goaterd13ada52016-01-25 15:07:27 +01001667 return;
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001668 }
1669 sens = ibs->sensors + cmd[2];
1670
1671 if ((cmd[3] & 0x80) == 0) {
1672 /* Just clear everything */
1673 sens->states = 0;
Cédric Le Goaterd13ada52016-01-25 15:07:27 +01001674 return;
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001675 }
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001676}
1677
1678static void get_sensor_evt_status(IPMIBmcSim *ibs,
1679 uint8_t *cmd, unsigned int cmd_len,
Cédric Le Goatera580d822016-03-10 15:03:55 +01001680 RspBuffer *rsp)
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001681{
1682 IPMISensor *sens;
1683
Cédric Le Goater73d60fa2016-02-16 09:05:44 +01001684 if ((cmd[2] >= MAX_SENSORS) ||
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001685 !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
Cédric Le Goater6acb9712016-03-10 15:03:57 +01001686 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
Cédric Le Goaterd13ada52016-01-25 15:07:27 +01001687 return;
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001688 }
1689 sens = ibs->sensors + cmd[2];
Cédric Le Goatera580d822016-03-10 15:03:55 +01001690 rsp_buffer_push(rsp, sens->reading);
1691 rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1692 rsp_buffer_push(rsp, sens->assert_states & 0xff);
1693 rsp_buffer_push(rsp, (sens->assert_states >> 8) & 0xff);
1694 rsp_buffer_push(rsp, sens->deassert_states & 0xff);
1695 rsp_buffer_push(rsp, (sens->deassert_states >> 8) & 0xff);
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001696}
1697
1698static void get_sensor_reading(IPMIBmcSim *ibs,
1699 uint8_t *cmd, unsigned int cmd_len,
Cédric Le Goatera580d822016-03-10 15:03:55 +01001700 RspBuffer *rsp)
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001701{
1702 IPMISensor *sens;
1703
Cédric Le Goater73d60fa2016-02-16 09:05:44 +01001704 if ((cmd[2] >= MAX_SENSORS) ||
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001705 !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
Cédric Le Goater6acb9712016-03-10 15:03:57 +01001706 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
Cédric Le Goaterd13ada52016-01-25 15:07:27 +01001707 return;
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001708 }
1709 sens = ibs->sensors + cmd[2];
Cédric Le Goatera580d822016-03-10 15:03:55 +01001710 rsp_buffer_push(rsp, sens->reading);
1711 rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1712 rsp_buffer_push(rsp, sens->states & 0xff);
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001713 if (IPMI_SENSOR_IS_DISCRETE(sens)) {
Cédric Le Goatera580d822016-03-10 15:03:55 +01001714 rsp_buffer_push(rsp, (sens->states >> 8) & 0xff);
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001715 }
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001716}
1717
Cédric Le Goater728710e2016-01-25 15:07:32 +01001718static void set_sensor_type(IPMIBmcSim *ibs,
Cédric Le Goatera580d822016-03-10 15:03:55 +01001719 uint8_t *cmd, unsigned int cmd_len,
1720 RspBuffer *rsp)
Cédric Le Goater728710e2016-01-25 15:07:32 +01001721{
1722 IPMISensor *sens;
1723
1724
Cédric Le Goater73d60fa2016-02-16 09:05:44 +01001725 if ((cmd[2] >= MAX_SENSORS) ||
Cédric Le Goater728710e2016-01-25 15:07:32 +01001726 !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
Cédric Le Goater6acb9712016-03-10 15:03:57 +01001727 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
Cédric Le Goater728710e2016-01-25 15:07:32 +01001728 return;
1729 }
1730 sens = ibs->sensors + cmd[2];
1731 sens->sensor_type = cmd[3];
1732 sens->evt_reading_type_code = cmd[4] & 0x7f;
1733}
1734
1735static void get_sensor_type(IPMIBmcSim *ibs,
Cédric Le Goatera580d822016-03-10 15:03:55 +01001736 uint8_t *cmd, unsigned int cmd_len,
1737 RspBuffer *rsp)
Cédric Le Goater728710e2016-01-25 15:07:32 +01001738{
1739 IPMISensor *sens;
1740
1741
Cédric Le Goater73d60fa2016-02-16 09:05:44 +01001742 if ((cmd[2] >= MAX_SENSORS) ||
Cédric Le Goater728710e2016-01-25 15:07:32 +01001743 !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
Cédric Le Goater6acb9712016-03-10 15:03:57 +01001744 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
Cédric Le Goater728710e2016-01-25 15:07:32 +01001745 return;
1746 }
1747 sens = ibs->sensors + cmd[2];
Cédric Le Goatera580d822016-03-10 15:03:55 +01001748 rsp_buffer_push(rsp, sens->sensor_type);
1749 rsp_buffer_push(rsp, sens->evt_reading_type_code);
Cédric Le Goater728710e2016-01-25 15:07:32 +01001750}
1751
Cédric Le Goatere3f73202019-11-18 10:24:29 +01001752/*
1753 * bytes parameter
1754 * 1 sensor number
1755 * 2 operation (see below for bits meaning)
1756 * 3 sensor reading
1757 * 4:5 assertion states (optional)
1758 * 6:7 deassertion states (optional)
1759 * 8:10 event data 1,2,3 (optional)
1760 */
1761static void set_sensor_reading(IPMIBmcSim *ibs,
1762 uint8_t *cmd, unsigned int cmd_len,
1763 RspBuffer *rsp)
1764{
1765 IPMISensor *sens;
1766 uint8_t evd1 = 0;
1767 uint8_t evd2 = 0;
1768 uint8_t evd3 = 0;
1769 uint8_t new_reading = 0;
1770 uint16_t new_assert_states = 0;
1771 uint16_t new_deassert_states = 0;
1772 bool change_reading = false;
1773 bool change_assert = false;
1774 bool change_deassert = false;
1775 enum {
1776 SENSOR_GEN_EVENT_NONE,
1777 SENSOR_GEN_EVENT_DATA,
1778 SENSOR_GEN_EVENT_BMC,
1779 } do_gen_event = SENSOR_GEN_EVENT_NONE;
1780
1781 if ((cmd[2] >= MAX_SENSORS) ||
1782 !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1783 rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1784 return;
1785 }
1786
1787 sens = ibs->sensors + cmd[2];
1788
1789 /* [1:0] Sensor Reading operation */
1790 switch ((cmd[3]) & 0x3) {
1791 case 0: /* Do not change */
1792 break;
1793 case 1: /* write given value to sensor reading byte */
1794 new_reading = cmd[4];
1795 if (sens->reading != new_reading) {
1796 change_reading = true;
1797 }
1798 break;
1799 case 2:
1800 case 3:
1801 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1802 return;
1803 }
1804
1805 /* [3:2] Deassertion bits operation */
1806 switch ((cmd[3] >> 2) & 0x3) {
1807 case 0: /* Do not change */
1808 break;
1809 case 1: /* write given value */
1810 if (cmd_len > 7) {
1811 new_deassert_states = cmd[7];
1812 change_deassert = true;
1813 }
1814 if (cmd_len > 8) {
1815 new_deassert_states |= (cmd[8] << 8);
1816 }
1817 break;
1818
1819 case 2: /* mask on */
1820 if (cmd_len > 7) {
1821 new_deassert_states = (sens->deassert_states | cmd[7]);
1822 change_deassert = true;
1823 }
1824 if (cmd_len > 8) {
1825 new_deassert_states |= (sens->deassert_states | (cmd[8] << 8));
1826 }
1827 break;
1828
1829 case 3: /* mask off */
1830 if (cmd_len > 7) {
1831 new_deassert_states = (sens->deassert_states & cmd[7]);
1832 change_deassert = true;
1833 }
1834 if (cmd_len > 8) {
1835 new_deassert_states |= (sens->deassert_states & (cmd[8] << 8));
1836 }
1837 break;
1838 }
1839
1840 if (change_deassert && (new_deassert_states == sens->deassert_states)) {
1841 change_deassert = false;
1842 }
1843
1844 /* [5:4] Assertion bits operation */
1845 switch ((cmd[3] >> 4) & 0x3) {
1846 case 0: /* Do not change */
1847 break;
1848 case 1: /* write given value */
1849 if (cmd_len > 5) {
1850 new_assert_states = cmd[5];
1851 change_assert = true;
1852 }
1853 if (cmd_len > 6) {
1854 new_assert_states |= (cmd[6] << 8);
1855 }
1856 break;
1857
1858 case 2: /* mask on */
1859 if (cmd_len > 5) {
1860 new_assert_states = (sens->assert_states | cmd[5]);
1861 change_assert = true;
1862 }
1863 if (cmd_len > 6) {
1864 new_assert_states |= (sens->assert_states | (cmd[6] << 8));
1865 }
1866 break;
1867
1868 case 3: /* mask off */
1869 if (cmd_len > 5) {
1870 new_assert_states = (sens->assert_states & cmd[5]);
1871 change_assert = true;
1872 }
1873 if (cmd_len > 6) {
1874 new_assert_states |= (sens->assert_states & (cmd[6] << 8));
1875 }
1876 break;
1877 }
1878
1879 if (change_assert && (new_assert_states == sens->assert_states)) {
1880 change_assert = false;
1881 }
1882
1883 if (cmd_len > 9) {
1884 evd1 = cmd[9];
1885 }
1886 if (cmd_len > 10) {
1887 evd2 = cmd[10];
1888 }
1889 if (cmd_len > 11) {
1890 evd3 = cmd[11];
1891 }
1892
1893 /* [7:6] Event Data Bytes operation */
1894 switch ((cmd[3] >> 6) & 0x3) {
1895 case 0: /*
1896 * Don’t use Event Data bytes from this command. BMC will
1897 * generate it's own Event Data bytes based on its sensor
1898 * implementation.
1899 */
1900 evd1 = evd2 = evd3 = 0x0;
1901 do_gen_event = SENSOR_GEN_EVENT_BMC;
1902 break;
1903 case 1: /*
1904 * Write given values to event data bytes including bits
1905 * [3:0] Event Data 1.
1906 */
1907 do_gen_event = SENSOR_GEN_EVENT_DATA;
1908 break;
1909 case 2: /*
1910 * Write given values to event data bytes excluding bits
1911 * [3:0] Event Data 1.
1912 */
1913 evd1 &= 0xf0;
1914 do_gen_event = SENSOR_GEN_EVENT_DATA;
1915 break;
1916 case 3:
1917 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1918 return;
1919 }
1920
1921 /*
1922 * Event Data Bytes operation and parameter are inconsistent. The
1923 * Specs are not clear on that topic but generating an error seems
1924 * correct.
1925 */
1926 if (do_gen_event == SENSOR_GEN_EVENT_DATA && cmd_len < 10) {
1927 rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1928 return;
1929 }
1930
1931 /* commit values */
1932 if (change_reading) {
1933 sens->reading = new_reading;
1934 }
1935
1936 if (change_assert) {
1937 sens->assert_states = new_assert_states;
1938 }
1939
1940 if (change_deassert) {
1941 sens->deassert_states = new_deassert_states;
1942 }
1943
1944 /* TODO: handle threshold sensor */
1945 if (!IPMI_SENSOR_IS_DISCRETE(sens)) {
1946 return;
1947 }
1948
1949 switch (do_gen_event) {
1950 case SENSOR_GEN_EVENT_DATA: {
1951 unsigned int bit = evd1 & 0xf;
1952 uint16_t mask = (1 << bit);
1953
1954 if (sens->assert_states & mask & sens->assert_enable) {
1955 gen_event(ibs, cmd[2], 0, evd1, evd2, evd3);
1956 }
1957
1958 if (sens->deassert_states & mask & sens->deassert_enable) {
1959 gen_event(ibs, cmd[2], 1, evd1, evd2, evd3);
1960 }
1961 break;
1962 }
1963 case SENSOR_GEN_EVENT_BMC:
1964 /*
1965 * TODO: generate event and event data bytes depending on the
1966 * sensor
1967 */
1968 break;
1969 case SENSOR_GEN_EVENT_NONE:
1970 break;
1971 }
1972}
Cédric Le Goater728710e2016-01-25 15:07:32 +01001973
Cédric Le Goater62a49312016-01-25 15:07:28 +01001974static const IPMICmdHandler chassis_cmds[] = {
Cédric Le Goater4f298a42016-03-10 15:03:54 +01001975 [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = { chassis_capabilities },
1976 [IPMI_CMD_GET_CHASSIS_STATUS] = { chassis_status },
1977 [IPMI_CMD_CHASSIS_CONTROL] = { chassis_control, 3 },
1978 [IPMI_CMD_GET_SYS_RESTART_CAUSE] = { chassis_get_sys_restart_cause }
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001979};
1980static const IPMINetfn chassis_netfn = {
Cédric Le Goater62a49312016-01-25 15:07:28 +01001981 .cmd_nums = ARRAY_SIZE(chassis_cmds),
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001982 .cmd_handlers = chassis_cmds
1983};
1984
Cédric Le Goater62a49312016-01-25 15:07:28 +01001985static const IPMICmdHandler sensor_event_cmds[] = {
Corey Minyard9380d2e2017-08-18 20:17:48 -05001986 [IPMI_CMD_PLATFORM_EVENT_MSG] = { platform_event_msg, 10 },
Cédric Le Goater4f298a42016-03-10 15:03:54 +01001987 [IPMI_CMD_SET_SENSOR_EVT_ENABLE] = { set_sensor_evt_enable, 4 },
1988 [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = { get_sensor_evt_enable, 3 },
1989 [IPMI_CMD_REARM_SENSOR_EVTS] = { rearm_sensor_evts, 4 },
1990 [IPMI_CMD_GET_SENSOR_EVT_STATUS] = { get_sensor_evt_status, 3 },
1991 [IPMI_CMD_GET_SENSOR_READING] = { get_sensor_reading, 3 },
1992 [IPMI_CMD_SET_SENSOR_TYPE] = { set_sensor_type, 5 },
1993 [IPMI_CMD_GET_SENSOR_TYPE] = { get_sensor_type, 3 },
Cédric Le Goatere3f73202019-11-18 10:24:29 +01001994 [IPMI_CMD_SET_SENSOR_READING] = { set_sensor_reading, 5 },
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001995};
1996static const IPMINetfn sensor_event_netfn = {
Cédric Le Goater62a49312016-01-25 15:07:28 +01001997 .cmd_nums = ARRAY_SIZE(sensor_event_cmds),
Corey Minyard8bfffbc2015-12-17 12:50:05 -06001998 .cmd_handlers = sensor_event_cmds
1999};
2000
Cédric Le Goater62a49312016-01-25 15:07:28 +01002001static const IPMICmdHandler app_cmds[] = {
Cédric Le Goater4f298a42016-03-10 15:03:54 +01002002 [IPMI_CMD_GET_DEVICE_ID] = { get_device_id },
2003 [IPMI_CMD_COLD_RESET] = { cold_reset },
2004 [IPMI_CMD_WARM_RESET] = { warm_reset },
2005 [IPMI_CMD_SET_ACPI_POWER_STATE] = { set_acpi_power_state, 4 },
2006 [IPMI_CMD_GET_ACPI_POWER_STATE] = { get_acpi_power_state },
2007 [IPMI_CMD_GET_DEVICE_GUID] = { get_device_guid },
2008 [IPMI_CMD_SET_BMC_GLOBAL_ENABLES] = { set_bmc_global_enables, 3 },
2009 [IPMI_CMD_GET_BMC_GLOBAL_ENABLES] = { get_bmc_global_enables },
2010 [IPMI_CMD_CLR_MSG_FLAGS] = { clr_msg_flags, 3 },
2011 [IPMI_CMD_GET_MSG_FLAGS] = { get_msg_flags },
2012 [IPMI_CMD_GET_MSG] = { get_msg },
2013 [IPMI_CMD_SEND_MSG] = { send_msg, 3 },
2014 [IPMI_CMD_READ_EVT_MSG_BUF] = { read_evt_msg_buf },
2015 [IPMI_CMD_RESET_WATCHDOG_TIMER] = { reset_watchdog_timer },
2016 [IPMI_CMD_SET_WATCHDOG_TIMER] = { set_watchdog_timer, 8 },
2017 [IPMI_CMD_GET_WATCHDOG_TIMER] = { get_watchdog_timer },
Corey Minyard8bfffbc2015-12-17 12:50:05 -06002018};
2019static const IPMINetfn app_netfn = {
Cédric Le Goater62a49312016-01-25 15:07:28 +01002020 .cmd_nums = ARRAY_SIZE(app_cmds),
Corey Minyard8bfffbc2015-12-17 12:50:05 -06002021 .cmd_handlers = app_cmds
2022};
2023
Cédric Le Goater62a49312016-01-25 15:07:28 +01002024static const IPMICmdHandler storage_cmds[] = {
Cédric Le Goater540c07d2017-04-05 14:41:32 +02002025 [IPMI_CMD_GET_FRU_AREA_INFO] = { get_fru_area_info, 3 },
2026 [IPMI_CMD_READ_FRU_DATA] = { read_fru_data, 5 },
2027 [IPMI_CMD_WRITE_FRU_DATA] = { write_fru_data, 5 },
Cédric Le Goater4f298a42016-03-10 15:03:54 +01002028 [IPMI_CMD_GET_SDR_REP_INFO] = { get_sdr_rep_info },
2029 [IPMI_CMD_RESERVE_SDR_REP] = { reserve_sdr_rep },
2030 [IPMI_CMD_GET_SDR] = { get_sdr, 8 },
2031 [IPMI_CMD_ADD_SDR] = { add_sdr },
2032 [IPMI_CMD_CLEAR_SDR_REP] = { clear_sdr_rep, 8 },
2033 [IPMI_CMD_GET_SEL_INFO] = { get_sel_info },
2034 [IPMI_CMD_RESERVE_SEL] = { reserve_sel },
2035 [IPMI_CMD_GET_SEL_ENTRY] = { get_sel_entry, 8 },
2036 [IPMI_CMD_ADD_SEL_ENTRY] = { add_sel_entry, 18 },
2037 [IPMI_CMD_CLEAR_SEL] = { clear_sel, 8 },
Corey Minyard7f11cb62017-08-18 20:13:10 -05002038 [IPMI_CMD_GET_SEL_TIME] = { get_sel_time },
2039 [IPMI_CMD_SET_SEL_TIME] = { set_sel_time, 6 },
Corey Minyard8bfffbc2015-12-17 12:50:05 -06002040};
2041
2042static const IPMINetfn storage_netfn = {
Cédric Le Goater62a49312016-01-25 15:07:28 +01002043 .cmd_nums = ARRAY_SIZE(storage_cmds),
Corey Minyard8bfffbc2015-12-17 12:50:05 -06002044 .cmd_handlers = storage_cmds
2045};
2046
2047static void register_cmds(IPMIBmcSim *s)
2048{
Cédric Le Goatered8da052019-10-28 08:00:26 +01002049 ipmi_sim_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn);
2050 ipmi_sim_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn);
2051 ipmi_sim_register_netfn(s, IPMI_NETFN_APP, &app_netfn);
2052 ipmi_sim_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn);
Corey Minyard8bfffbc2015-12-17 12:50:05 -06002053}
2054
Cédric Le Goater51675602016-03-10 15:04:01 +01002055static uint8_t init_sdrs[] = {
Corey Minyard8bfffbc2015-12-17 12:50:05 -06002056 /* Watchdog device */
2057 0x00, 0x00, 0x51, 0x02, 35, 0x20, 0x00, 0x00,
2058 0x23, 0x01, 0x63, 0x00, 0x23, 0x6f, 0x0f, 0x01,
2059 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2060 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8,
2061 'W', 'a', 't', 'c', 'h', 'd', 'o', 'g',
Corey Minyard8bfffbc2015-12-17 12:50:05 -06002062};
2063
Cédric Le Goater4fa9f082016-03-10 15:03:59 +01002064static void ipmi_sdr_init(IPMIBmcSim *ibs)
2065{
2066 unsigned int i;
Cédric Le Goater52fc01d2016-03-10 15:04:00 +01002067 int len;
Cédric Le Goater51675602016-03-10 15:04:01 +01002068 size_t sdrs_size;
2069 uint8_t *sdrs;
Cédric Le Goater4fa9f082016-03-10 15:03:59 +01002070
Cédric Le Goater51675602016-03-10 15:04:01 +01002071 sdrs_size = sizeof(init_sdrs);
2072 sdrs = init_sdrs;
Cédric Le Goater8c6fd7f2017-04-05 14:41:31 +02002073 if (ibs->sdr_filename &&
2074 !g_file_get_contents(ibs->sdr_filename, (gchar **) &sdrs, &sdrs_size,
2075 NULL)) {
2076 error_report("failed to load sdr file '%s'", ibs->sdr_filename);
2077 sdrs_size = sizeof(init_sdrs);
2078 sdrs = init_sdrs;
2079 }
Cédric Le Goater51675602016-03-10 15:04:01 +01002080
2081 for (i = 0; i < sdrs_size; i += len) {
Cédric Le Goater4fa9f082016-03-10 15:03:59 +01002082 struct ipmi_sdr_header *sdrh;
Cédric Le Goater52fc01d2016-03-10 15:04:00 +01002083
Cédric Le Goater51675602016-03-10 15:04:01 +01002084 if (i + IPMI_SDR_HEADER_SIZE > sdrs_size) {
Cédric Le Goater4fa9f082016-03-10 15:03:59 +01002085 error_report("Problem with recid 0x%4.4x", i);
Cédric Le Goater8c6fd7f2017-04-05 14:41:31 +02002086 break;
Cédric Le Goater4fa9f082016-03-10 15:03:59 +01002087 }
Cédric Le Goater51675602016-03-10 15:04:01 +01002088 sdrh = (struct ipmi_sdr_header *) &sdrs[i];
Cédric Le Goater4fa9f082016-03-10 15:03:59 +01002089 len = ipmi_sdr_length(sdrh);
Cédric Le Goater51675602016-03-10 15:04:01 +01002090 if (i + len > sdrs_size) {
Cédric Le Goater4fa9f082016-03-10 15:03:59 +01002091 error_report("Problem with recid 0x%4.4x", i);
Cédric Le Goater8c6fd7f2017-04-05 14:41:31 +02002092 break;
Cédric Le Goater4fa9f082016-03-10 15:03:59 +01002093 }
2094 sdr_add_entry(ibs, sdrh, len, NULL);
Cédric Le Goater4fa9f082016-03-10 15:03:59 +01002095 }
Cédric Le Goater8c6fd7f2017-04-05 14:41:31 +02002096
2097 if (sdrs != init_sdrs) {
2098 g_free(sdrs);
2099 }
Cédric Le Goater4fa9f082016-03-10 15:03:59 +01002100}
2101
Corey Minyardbd66bcf2015-12-17 12:50:11 -06002102static const VMStateDescription vmstate_ipmi_sim = {
2103 .name = TYPE_IPMI_BMC_SIMULATOR,
2104 .version_id = 1,
2105 .minimum_version_id = 1,
2106 .fields = (VMStateField[]) {
2107 VMSTATE_UINT8(bmc_global_enables, IPMIBmcSim),
2108 VMSTATE_UINT8(msg_flags, IPMIBmcSim),
2109 VMSTATE_BOOL(watchdog_initialized, IPMIBmcSim),
2110 VMSTATE_UINT8(watchdog_use, IPMIBmcSim),
2111 VMSTATE_UINT8(watchdog_action, IPMIBmcSim),
2112 VMSTATE_UINT8(watchdog_pretimeout, IPMIBmcSim),
2113 VMSTATE_BOOL(watchdog_expired, IPMIBmcSim),
2114 VMSTATE_UINT16(watchdog_timeout, IPMIBmcSim),
2115 VMSTATE_BOOL(watchdog_running, IPMIBmcSim),
2116 VMSTATE_BOOL(watchdog_preaction_ran, IPMIBmcSim),
2117 VMSTATE_INT64(watchdog_expiry, IPMIBmcSim),
2118 VMSTATE_UINT8_ARRAY(evtbuf, IPMIBmcSim, 16),
2119 VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].status, IPMIBmcSim),
2120 VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].reading, IPMIBmcSim),
2121 VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].states, IPMIBmcSim),
2122 VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_states, IPMIBmcSim),
2123 VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].deassert_states,
2124 IPMIBmcSim),
2125 VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_enable, IPMIBmcSim),
2126 VMSTATE_END_OF_LIST()
2127 }
2128};
2129
Cédric Le Goater540c07d2017-04-05 14:41:32 +02002130static void ipmi_fru_init(IPMIFru *fru)
2131{
2132 int fsize;
2133 int size = 0;
2134
2135 if (!fru->filename) {
2136 goto out;
2137 }
2138
2139 fsize = get_image_size(fru->filename);
2140 if (fsize > 0) {
2141 size = QEMU_ALIGN_UP(fsize, fru->areasize);
2142 fru->data = g_malloc0(size);
2143 if (load_image_size(fru->filename, fru->data, fsize) != fsize) {
2144 error_report("Could not load file '%s'", fru->filename);
2145 g_free(fru->data);
2146 fru->data = NULL;
2147 }
2148 }
2149
2150out:
2151 if (!fru->data) {
2152 /* give one default FRU */
2153 size = fru->areasize;
2154 fru->data = g_malloc0(size);
2155 }
2156
2157 fru->nentries = size / fru->areasize;
2158}
2159
Cédric Le Goater0bc60012016-03-10 15:03:58 +01002160static void ipmi_sim_realize(DeviceState *dev, Error **errp)
Corey Minyard8bfffbc2015-12-17 12:50:05 -06002161{
Cédric Le Goater0bc60012016-03-10 15:03:58 +01002162 IPMIBmc *b = IPMI_BMC(dev);
Corey Minyard8bfffbc2015-12-17 12:50:05 -06002163 unsigned int i;
Corey Minyard8bfffbc2015-12-17 12:50:05 -06002164 IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
2165
Corey Minyard8bfffbc2015-12-17 12:50:05 -06002166 QTAILQ_INIT(&ibs->rcvbufs);
2167
2168 ibs->bmc_global_enables = (1 << IPMI_BMC_EVENT_LOG_BIT);
2169 ibs->device_id = 0x20;
2170 ibs->ipmi_version = 0x02; /* IPMI 2.0 */
Cédric Le Goaterb7088392016-01-25 15:07:33 +01002171 ibs->restart_cause = 0;
Corey Minyard8bfffbc2015-12-17 12:50:05 -06002172 for (i = 0; i < 4; i++) {
2173 ibs->sel.last_addition[i] = 0xff;
2174 ibs->sel.last_clear[i] = 0xff;
2175 ibs->sdr.last_addition[i] = 0xff;
2176 ibs->sdr.last_clear[i] = 0xff;
2177 }
2178
Cédric Le Goater4fa9f082016-03-10 15:03:59 +01002179 ipmi_sdr_init(ibs);
Corey Minyard8bfffbc2015-12-17 12:50:05 -06002180
Cédric Le Goater540c07d2017-04-05 14:41:32 +02002181 ipmi_fru_init(&ibs->fru);
2182
Cédric Le Goater52ba4d52016-01-25 15:07:34 +01002183 ibs->acpi_power_state[0] = 0;
2184 ibs->acpi_power_state[1] = 0;
2185
Corey Minyard8bfffbc2015-12-17 12:50:05 -06002186 ipmi_init_sensors_from_sdrs(ibs);
2187 register_cmds(ibs);
2188
2189 ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs);
Corey Minyardbd66bcf2015-12-17 12:50:11 -06002190
2191 vmstate_register(NULL, 0, &vmstate_ipmi_sim, ibs);
Corey Minyard8bfffbc2015-12-17 12:50:05 -06002192}
2193
Cédric Le Goater8c6fd7f2017-04-05 14:41:31 +02002194static Property ipmi_sim_properties[] = {
Cédric Le Goater540c07d2017-04-05 14:41:32 +02002195 DEFINE_PROP_UINT16("fruareasize", IPMIBmcSim, fru.areasize, 1024),
2196 DEFINE_PROP_STRING("frudatafile", IPMIBmcSim, fru.filename),
Cédric Le Goater8c6fd7f2017-04-05 14:41:31 +02002197 DEFINE_PROP_STRING("sdrfile", IPMIBmcSim, sdr_filename),
Corey Minyard20b23362017-08-28 12:48:44 -05002198 DEFINE_PROP_UINT8("device_id", IPMIBmcSim, device_id, 0x20),
2199 DEFINE_PROP_UINT8("ipmi_version", IPMIBmcSim, ipmi_version, 0x02),
2200 DEFINE_PROP_UINT8("device_rev", IPMIBmcSim, device_rev, 0),
2201 DEFINE_PROP_UINT8("fwrev1", IPMIBmcSim, fwrev1, 0),
2202 DEFINE_PROP_UINT8("fwrev2", IPMIBmcSim, fwrev2, 0),
2203 DEFINE_PROP_UINT32("mfg_id", IPMIBmcSim, mfg_id, 0),
2204 DEFINE_PROP_UINT16("product_id", IPMIBmcSim, product_id, 0),
Corey Minyard7b0cd782017-09-06 15:57:07 -05002205 DEFINE_PROP_UUID_NODEFAULT("guid", IPMIBmcSim, uuid),
Cédric Le Goater8c6fd7f2017-04-05 14:41:31 +02002206 DEFINE_PROP_END_OF_LIST(),
2207};
2208
Corey Minyard8bfffbc2015-12-17 12:50:05 -06002209static void ipmi_sim_class_init(ObjectClass *oc, void *data)
2210{
Cédric Le Goater0bc60012016-03-10 15:03:58 +01002211 DeviceClass *dc = DEVICE_CLASS(oc);
Corey Minyard8bfffbc2015-12-17 12:50:05 -06002212 IPMIBmcClass *bk = IPMI_BMC_CLASS(oc);
2213
Corey Minyard66abfdd2016-10-24 15:10:15 -05002214 dc->hotpluggable = false;
Cédric Le Goater0bc60012016-03-10 15:03:58 +01002215 dc->realize = ipmi_sim_realize;
Marc-André Lureau4f67d302020-01-10 19:30:32 +04002216 device_class_set_props(dc, ipmi_sim_properties);
Corey Minyard8bfffbc2015-12-17 12:50:05 -06002217 bk->handle_command = ipmi_sim_handle_command;
2218}
2219
2220static const TypeInfo ipmi_sim_type = {
2221 .name = TYPE_IPMI_BMC_SIMULATOR,
2222 .parent = TYPE_IPMI_BMC,
2223 .instance_size = sizeof(IPMIBmcSim),
Corey Minyard8bfffbc2015-12-17 12:50:05 -06002224 .class_init = ipmi_sim_class_init,
2225};
2226
2227static void ipmi_sim_register_types(void)
2228{
2229 type_register_static(&ipmi_sim_type);
2230}
2231
2232type_init(ipmi_sim_register_types)