1 /* 2 * ASPEED iBT Device 3 * 4 * Copyright (c) 2016-2021 Cédric Le Goater, IBM Corporation. 5 * 6 * This code is licensed under the GPL version 2 or later. See 7 * the COPYING file in the top-level directory. 8 */ 9 10 #include "qemu/osdep.h" 11 #include "hw/sysbus.h" 12 #include "sysemu/qtest.h" 13 #include "sysemu/sysemu.h" 14 #include "qemu/log.h" 15 #include "qapi/error.h" 16 #include "qemu/error-report.h" 17 #include "hw/irq.h" 18 #include "hw/qdev-properties.h" 19 #include "hw/qdev-properties-system.h" 20 #include "migration/vmstate.h" 21 #include "hw/misc/aspeed_ibt.h" 22 #include "trace.h" 23 24 #define BT_IO_REGION_SIZE 0x1C 25 26 #define TO_REG(o) (o >> 2) 27 28 #define BT_CR0 0x0 /* iBT config */ 29 #define BT_CR0_IO_BASE 16 30 #define BT_CR0_IRQ 12 31 #define BT_CR0_EN_CLR_SLV_RDP 0x8 32 #define BT_CR0_EN_CLR_SLV_WRP 0x4 33 #define BT_CR0_ENABLE_IBT 0x1 34 #define BT_CR1 0x4 /* interrupt enable */ 35 #define BT_CR1_IRQ_H2B 0x01 36 #define BT_CR1_IRQ_HBUSY 0x40 37 #define BT_CR2 0x8 /* interrupt status */ 38 #define BT_CR2_IRQ_H2B 0x01 39 #define BT_CR2_IRQ_HBUSY 0x40 40 #define BT_CR3 0xc /* unused */ 41 #define BT_CTRL 0x10 42 #define BT_CTRL_B_BUSY 0x80 43 #define BT_CTRL_H_BUSY 0x40 44 #define BT_CTRL_OEM0 0x20 45 #define BT_CTRL_SMS_ATN 0x10 46 #define BT_CTRL_B2H_ATN 0x08 47 #define BT_CTRL_H2B_ATN 0x04 48 #define BT_CTRL_CLR_RD_PTR 0x02 49 #define BT_CTRL_CLR_WR_PTR 0x01 50 #define BT_BMC2HOST 0x14 51 #define BT_INTMASK 0x18 52 #define BT_INTMASK_B2H_IRQEN 0x01 53 #define BT_INTMASK_B2H_IRQ 0x02 54 #define BT_INTMASK_BMC_HWRST 0x80 55 56 /* 57 * VM IPMI defines 58 */ 59 #define VM_MSG_CHAR 0xA0 /* Marks end of message */ 60 #define VM_CMD_CHAR 0xA1 /* Marks end of a command */ 61 #define VM_ESCAPE_CHAR 0xAA /* Set bit 4 from the next byte to 0 */ 62 63 #define VM_PROTOCOL_VERSION 1 64 #define VM_CMD_VERSION 0xff /* A version number byte follows */ 65 #define VM_CMD_NOATTN 0x00 66 #define VM_CMD_ATTN 0x01 67 #define VM_CMD_ATTN_IRQ 0x02 68 #define VM_CMD_POWEROFF 0x03 69 #define VM_CMD_RESET 0x04 70 #define VM_CMD_ENABLE_IRQ 0x05 /* Enable/disable the messaging irq */ 71 #define VM_CMD_DISABLE_IRQ 0x06 72 #define VM_CMD_SEND_NMI 0x07 73 #define VM_CMD_CAPABILITIES 0x08 74 #define VM_CAPABILITIES_POWER 0x01 75 #define VM_CAPABILITIES_RESET 0x02 76 #define VM_CAPABILITIES_IRQ 0x04 77 #define VM_CAPABILITIES_NMI 0x08 78 #define VM_CAPABILITIES_ATTN 0x10 79 #define VM_CAPABILITIES_GRACEFUL_SHUTDOWN 0x20 80 #define VM_CMD_GRACEFUL_SHUTDOWN 0x09 81 82 /* 83 * These routines are inspired by the 'ipmi-bmc-extern' model and by 84 * the lanserv simulator of OpenIPMI. See : 85 * https://github.com/cminyard/openipmi/blob/master/lanserv/serial_ipmi.c 86 */ 87 static unsigned char ipmb_checksum(const unsigned char *data, int size, 88 unsigned char start) 89 { 90 unsigned char csum = start; 91 92 for (; size > 0; size--, data++) { 93 csum += *data; 94 } 95 return csum; 96 } 97 98 static void vm_add_char(unsigned char ch, unsigned char *c, unsigned int *pos) 99 { 100 switch (ch) { 101 case VM_MSG_CHAR: 102 case VM_CMD_CHAR: 103 case VM_ESCAPE_CHAR: 104 c[(*pos)++] = VM_ESCAPE_CHAR; 105 c[(*pos)++] = ch | 0x10; 106 break; 107 108 default: 109 c[(*pos)++] = ch; 110 } 111 } 112 113 static void aspeed_ibt_dump_msg(const char *func, unsigned char *msg, 114 unsigned int len) 115 { 116 if (trace_event_get_state_backends(TRACE_ASPEED_IBT_CHR_DUMP_MSG)) { 117 int size = len * 3 + 1; 118 g_autofree char *tmp = g_malloc(size); 119 int i, n = 0; 120 121 for (i = 0; i < len; i++) { 122 n += snprintf(tmp + n, size - n, "%02x:", msg[i]); 123 } 124 tmp[size - 1] = 0; 125 126 trace_aspeed_ibt_chr_dump_msg(func, tmp, len); 127 } 128 } 129 130 static void aspeed_ibt_chr_write(AspeedIBTState *ibt, const uint8_t *buf, 131 int len) 132 { 133 int i; 134 135 if (!qemu_chr_fe_get_driver(&ibt->chr)) { 136 return; 137 } 138 139 aspeed_ibt_dump_msg(__func__, ibt->recv_msg, ibt->recv_msg_len); 140 141 for (i = 0; i < len; i++) { 142 qemu_chr_fe_write(&ibt->chr, &buf[i], 1); 143 } 144 } 145 146 static void vm_send(AspeedIBTState *ibt) 147 { 148 unsigned int i; 149 unsigned int len = 0; 150 g_autofree unsigned char *c = g_malloc((ibt->send_msg_len + 7) * 2); 151 uint8_t netfn; 152 153 /* 154 * The VM IPMI message format does not follow the IPMI BT 155 * interface format. The sequence and the netfn bytes need to be 156 * swapped. 157 */ 158 netfn = ibt->send_msg[1]; 159 ibt->send_msg[1] = ibt->send_msg[2]; 160 ibt->send_msg[2] = netfn; 161 162 /* No length byte in the VM IPMI message format. trim it */ 163 for (i = 1; i < ibt->send_msg_len; i++) { 164 vm_add_char(ibt->send_msg[i], c, &len); 165 } 166 167 vm_add_char(-ipmb_checksum(&ibt->send_msg[1], ibt->send_msg_len - 1, 0), 168 c, &len); 169 c[len++] = VM_MSG_CHAR; 170 171 aspeed_ibt_chr_write(ibt, c, len); 172 } 173 174 static void aspeed_ibt_update_irq(AspeedIBTState *ibt) 175 { 176 bool raise = false; 177 178 /* H2B rising */ 179 if ((ibt->regs[TO_REG(BT_CTRL)] & BT_CTRL_H2B_ATN) && 180 ((ibt->regs[TO_REG(BT_CR1)] & BT_CR1_IRQ_H2B) == BT_CR1_IRQ_H2B)) { 181 ibt->regs[TO_REG(BT_CR2)] |= BT_CR2_IRQ_H2B; 182 183 /* 184 * Also flag the fact that we are waiting for the guest/driver 185 * to read a received message 186 */ 187 ibt->recv_waiting = true; 188 raise = true; 189 } 190 191 /* H_BUSY falling (not supported) */ 192 if ((ibt->regs[TO_REG(BT_CTRL)] & BT_CTRL_H_BUSY) && 193 ((ibt->regs[TO_REG(BT_CR1)] & BT_CR1_IRQ_HBUSY) == BT_CR1_IRQ_HBUSY)) { 194 ibt->regs[TO_REG(BT_CR2)] |= BT_CR2_IRQ_HBUSY; 195 196 raise = true; 197 } 198 199 if (raise) { 200 qemu_irq_raise(ibt->irq); 201 } 202 } 203 204 static void vm_handle_msg(AspeedIBTState *ibt, unsigned char *msg, 205 unsigned int len) 206 { 207 uint8_t seq; 208 209 aspeed_ibt_dump_msg(__func__, ibt->recv_msg, ibt->recv_msg_len); 210 211 if (len < 4) { 212 qemu_log_mask(LOG_GUEST_ERROR, " %s: Message too short\n", __func__); 213 return; 214 } 215 216 if (ipmb_checksum(ibt->recv_msg, ibt->recv_msg_len, 0) != 0) { 217 qemu_log_mask(LOG_GUEST_ERROR, " %s: Message checksum failure\n", 218 __func__); 219 return; 220 } 221 222 /* Trim the checksum byte */ 223 ibt->recv_msg_len--; 224 225 /* 226 * The VM IPMI message format does not follow the IPMI BT 227 * interface format. The sequence and the netfn bytes need to be 228 * swapped. 229 */ 230 seq = ibt->recv_msg[0]; 231 ibt->recv_msg[0] = ibt->recv_msg[1]; 232 ibt->recv_msg[1] = seq; 233 234 aspeed_ibt_update_irq(ibt); 235 } 236 237 /* TODO: handle commands */ 238 static void vm_handle_cmd(AspeedIBTState *ibt, unsigned char *msg, 239 unsigned int len) 240 { 241 aspeed_ibt_dump_msg(__func__, ibt->recv_msg, ibt->recv_msg_len); 242 243 if (len < 1) { 244 qemu_log_mask(LOG_GUEST_ERROR, " %s: Command too short\n", __func__); 245 return; 246 } 247 248 switch (msg[0]) { 249 case VM_CMD_VERSION: 250 break; 251 252 case VM_CMD_CAPABILITIES: 253 if (len < 2) { 254 return; 255 } 256 break; 257 258 case VM_CMD_RESET: 259 break; 260 } 261 } 262 263 static void vm_handle_char(AspeedIBTState *ibt, unsigned char ch) 264 { 265 unsigned int len = ibt->recv_msg_len; 266 267 switch (ch) { 268 case VM_MSG_CHAR: 269 case VM_CMD_CHAR: 270 if (ibt->in_escape) { 271 qemu_log_mask(LOG_GUEST_ERROR, " %s: Message ended in escape\n", 272 __func__); 273 } else if (ibt->recv_msg_too_many) { 274 qemu_log_mask(LOG_GUEST_ERROR, " %s: Message too long\n", __func__); 275 } else if (ibt->recv_msg_len == 0) { 276 /* Nothing to do */ 277 } else if (ch == VM_MSG_CHAR) { 278 /* Last byte of message. Signal BMC as the host would do */ 279 ibt->regs[TO_REG(BT_CTRL)] |= BT_CTRL_H2B_ATN; 280 281 vm_handle_msg(ibt, ibt->recv_msg, ibt->recv_msg_len); 282 283 /* Message is only handled when read by BMC (!B_BUSY) */ 284 } else if (ch == VM_CMD_CHAR) { 285 vm_handle_cmd(ibt, ibt->recv_msg, ibt->recv_msg_len); 286 287 /* Command is now handled. reset receive state */ 288 ibt->in_escape = 0; 289 ibt->recv_msg_len = 0; 290 ibt->recv_msg_too_many = 0; 291 } 292 break; 293 294 case VM_ESCAPE_CHAR: 295 if (!ibt->recv_msg_too_many) { 296 ibt->in_escape = 1; 297 } 298 break; 299 300 default: 301 if (ibt->in_escape) { 302 ibt->in_escape = 0; 303 ch &= ~0x10; 304 } 305 306 if (!ibt->recv_msg_too_many) { 307 if (len >= sizeof(ibt->recv_msg)) { 308 ibt->recv_msg_too_many = 1; 309 break; 310 } 311 312 ibt->recv_msg[len] = ch; 313 ibt->recv_msg_len++; 314 } 315 break; 316 } 317 } 318 319 static void vm_connected(AspeedIBTState *ibt) 320 { 321 unsigned int len = 0; 322 unsigned char c[5]; 323 324 vm_add_char(VM_CMD_VERSION, c, &len); 325 vm_add_char(VM_PROTOCOL_VERSION, c, &len); 326 c[len++] = VM_CMD_CHAR; 327 328 aspeed_ibt_chr_write(ibt, c, len); 329 } 330 331 static void aspeed_ibt_chr_event(void *opaque, QEMUChrEvent event) 332 { 333 AspeedIBTState *ibt = ASPEED_IBT(opaque); 334 335 switch (event) { 336 case CHR_EVENT_OPENED: 337 vm_connected(ibt); 338 ibt->connected = true; 339 break; 340 341 case CHR_EVENT_CLOSED: 342 if (!ibt->connected) { 343 return; 344 } 345 ibt->connected = false; 346 break; 347 case CHR_EVENT_BREAK: 348 case CHR_EVENT_MUX_IN: 349 case CHR_EVENT_MUX_OUT: 350 /* Ignore */ 351 break; 352 } 353 trace_aspeed_ibt_chr_event(ibt->connected); 354 } 355 356 static int aspeed_ibt_chr_can_receive(void *opaque) 357 { 358 AspeedIBTState *ibt = ASPEED_IBT(opaque); 359 360 return !ibt->recv_waiting && !(ibt->regs[TO_REG(BT_CTRL)] & BT_CTRL_B_BUSY); 361 } 362 363 static void aspeed_ibt_chr_receive(void *opaque, const uint8_t *buf, 364 int size) 365 { 366 AspeedIBTState *ibt = ASPEED_IBT(opaque); 367 int i; 368 369 if (!ibt->connected) { 370 qemu_log_mask(LOG_GUEST_ERROR, " %s: not connected !?\n", __func__); 371 return; 372 } 373 374 for (i = 0; i < size; i++) { 375 vm_handle_char(ibt, buf[i]); 376 } 377 } 378 379 static void aspeed_ibt_write(void *opaque, hwaddr offset, uint64_t data, 380 unsigned size) 381 { 382 AspeedIBTState *ibt = ASPEED_IBT(opaque); 383 384 trace_aspeed_ibt_write(offset, data); 385 386 switch (offset) { 387 case BT_CTRL: 388 /* CLR_WR_PTR: cleared before a message is written */ 389 if (data & BT_CTRL_CLR_WR_PTR) { 390 memset(ibt->send_msg, 0, sizeof(ibt->send_msg)); 391 ibt->send_msg_len = 0; 392 trace_aspeed_ibt_event("CLR_WR_PTR"); 393 } 394 395 /* CLR_RD_PTR: cleared before a message is read */ 396 else if (data & BT_CTRL_CLR_RD_PTR) { 397 ibt->recv_msg_index = -1; 398 trace_aspeed_ibt_event("CLR_RD_PTR"); 399 } 400 401 /* 402 * H2B_ATN: raised by host to end message, cleared by BMC 403 * before reading message 404 */ 405 else if (data & BT_CTRL_H2B_ATN) { 406 ibt->regs[TO_REG(BT_CTRL)] &= ~BT_CTRL_H2B_ATN; 407 trace_aspeed_ibt_event("H2B_ATN"); 408 } 409 410 /* B_BUSY: raised and cleared by BMC when message is read */ 411 else if (data & BT_CTRL_B_BUSY) { 412 ibt->regs[TO_REG(BT_CTRL)] ^= BT_CTRL_B_BUSY; 413 trace_aspeed_ibt_event("B_BUSY"); 414 } 415 416 /* 417 * B2H_ATN: raised by BMC and cleared by host 418 * 419 * Also simulate the host busy bit which is set while the host 420 * is reading the message from the BMC 421 */ 422 else if (data & BT_CTRL_B2H_ATN) { 423 trace_aspeed_ibt_event("B2H_ATN"); 424 ibt->regs[TO_REG(BT_CTRL)] |= (BT_CTRL_B2H_ATN | BT_CTRL_H_BUSY); 425 426 vm_send(ibt); 427 428 ibt->regs[TO_REG(BT_CTRL)] &= ~(BT_CTRL_B2H_ATN | BT_CTRL_H_BUSY); 429 430 /* signal H_BUSY falling but that's a bit useless */ 431 aspeed_ibt_update_irq(ibt); 432 } 433 434 /* Anything else is unexpected */ 435 else { 436 qemu_log_mask(LOG_GUEST_ERROR, "%s: unexpected CTRL setting\n", 437 __func__); 438 } 439 440 /* Message was read by BMC. we can reset the receive state */ 441 if (!(ibt->regs[TO_REG(BT_CTRL)] & BT_CTRL_B_BUSY)) { 442 trace_aspeed_ibt_event("B_BUSY cleared"); 443 ibt->recv_waiting = false; 444 ibt->in_escape = 0; 445 ibt->recv_msg_len = 0; 446 ibt->recv_msg_too_many = 0; 447 } 448 break; 449 450 case BT_BMC2HOST: 451 if (ibt->send_msg_len < sizeof(ibt->send_msg)) { 452 trace_aspeed_ibt_event("BMC2HOST"); 453 ibt->send_msg[ibt->send_msg_len++] = data & 0xff; 454 } 455 break; 456 457 case BT_CR0: /* TODO: iBT config */ 458 case BT_CR1: /* interrupt enable */ 459 case BT_CR3: /* unused */ 460 case BT_INTMASK: 461 ibt->regs[TO_REG(offset)] = (uint32_t) data; 462 break; 463 case BT_CR2: /* interrupt status. writing 1 clears. */ 464 ibt->regs[TO_REG(offset)] ^= (uint32_t) data; 465 qemu_irq_lower(ibt->irq); 466 break; 467 468 default: 469 qemu_log_mask(LOG_UNIMP, "%s: not implemented 0x%" HWADDR_PRIx "\n", 470 __func__, offset); 471 break; 472 } 473 } 474 475 static uint64_t aspeed_ibt_read(void *opaque, hwaddr offset, unsigned size) 476 { 477 AspeedIBTState *ibt = ASPEED_IBT(opaque); 478 uint64_t val = 0; 479 480 switch (offset) { 481 case BT_BMC2HOST: 482 trace_aspeed_ibt_event("BMC2HOST"); 483 /* 484 * The IPMI BT interface requires the first byte to be the 485 * length of the message 486 */ 487 if (ibt->recv_msg_index == -1) { 488 val = ibt->recv_msg_len; 489 ibt->recv_msg_index++; 490 } else if (ibt->recv_msg_index < ibt->recv_msg_len) { 491 val = ibt->recv_msg[ibt->recv_msg_index++]; 492 } 493 break; 494 495 case BT_CR0: 496 case BT_CR1: 497 case BT_CR2: 498 case BT_CR3: 499 case BT_CTRL: 500 case BT_INTMASK: 501 return ibt->regs[TO_REG(offset)]; 502 default: 503 qemu_log_mask(LOG_UNIMP, "%s: not implemented 0x%" HWADDR_PRIx "\n", 504 __func__, offset); 505 return 0; 506 } 507 508 trace_aspeed_ibt_read(offset, val); 509 return val; 510 } 511 512 static const MemoryRegionOps aspeed_ibt_ops = { 513 .read = aspeed_ibt_read, 514 .write = aspeed_ibt_write, 515 .endianness = DEVICE_LITTLE_ENDIAN, 516 .valid = { 517 .min_access_size = 1, 518 .max_access_size = 4, 519 }, 520 }; 521 522 static void aspeed_ibt_reset(DeviceState *dev) 523 { 524 AspeedIBTState *ibt = ASPEED_IBT(dev); 525 526 memset(ibt->regs, 0, sizeof(ibt->regs)); 527 528 memset(ibt->recv_msg, 0, sizeof(ibt->recv_msg)); 529 ibt->recv_msg_len = 0; 530 ibt->recv_msg_index = -1; 531 ibt->recv_msg_too_many = 0; 532 ibt->recv_waiting = false; 533 ibt->in_escape = 0; 534 535 memset(ibt->send_msg, 0, sizeof(ibt->send_msg)); 536 ibt->send_msg_len = 0; 537 } 538 539 static void aspeed_ibt_realize(DeviceState *dev, Error **errp) 540 { 541 SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 542 AspeedIBTState *ibt = ASPEED_IBT(dev); 543 544 if (!qemu_chr_fe_get_driver(&ibt->chr) && !qtest_enabled()) { 545 warn_report("Aspeed iBT has no chardev backend"); 546 } else { 547 qemu_chr_fe_set_handlers(&ibt->chr, aspeed_ibt_chr_can_receive, 548 aspeed_ibt_chr_receive, aspeed_ibt_chr_event, 549 NULL, ibt, NULL, true); 550 } 551 552 sysbus_init_irq(sbd, &ibt->irq); 553 memory_region_init_io(&ibt->iomem, OBJECT(ibt), &aspeed_ibt_ops, ibt, 554 TYPE_ASPEED_IBT, BT_IO_REGION_SIZE); 555 556 sysbus_init_mmio(sbd, &ibt->iomem); 557 } 558 559 static Property aspeed_ibt_props[] = { 560 DEFINE_PROP_CHR("chardev", AspeedIBTState, chr), 561 DEFINE_PROP_END_OF_LIST(), 562 }; 563 564 static const VMStateDescription vmstate_aspeed_ibt = { 565 .name = "aspeed.bt", 566 .version_id = 1, 567 .minimum_version_id = 1, 568 .fields = (VMStateField[]) { 569 VMSTATE_UINT32_ARRAY(regs, AspeedIBTState, ASPEED_IBT_NR_REGS), 570 VMSTATE_END_OF_LIST() 571 } 572 }; 573 574 static void aspeed_ibt_class_init(ObjectClass *klass, void *data) 575 { 576 DeviceClass *dc = DEVICE_CLASS(klass); 577 dc->realize = aspeed_ibt_realize; 578 device_class_set_legacy_reset(dc, aspeed_ibt_reset); 579 dc->desc = "ASPEED iBT Device"; 580 dc->vmsd = &vmstate_aspeed_ibt; 581 device_class_set_props(dc, aspeed_ibt_props); 582 } 583 584 static const TypeInfo aspeed_ibt_info = { 585 .name = TYPE_ASPEED_IBT, 586 .parent = TYPE_SYS_BUS_DEVICE, 587 .instance_size = sizeof(AspeedIBTState), 588 .class_init = aspeed_ibt_class_init, 589 }; 590 591 static void aspeed_ibt_register_types(void) 592 { 593 type_register_static(&aspeed_ibt_info); 594 } 595 596 type_init(aspeed_ibt_register_types); 597