1 /* 2 * QEMU IPMI KCS emulation 3 * 4 * Copyright (c) 2015,2017 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 #include "qemu/osdep.h" 25 #include "migration/vmstate.h" 26 #include "qemu/log.h" 27 #include "qapi/error.h" 28 #include "hw/ipmi/ipmi_kcs.h" 29 30 #define IPMI_KCS_OBF_BIT 0 31 #define IPMI_KCS_IBF_BIT 1 32 #define IPMI_KCS_SMS_ATN_BIT 2 33 #define IPMI_KCS_CD_BIT 3 34 35 #define IPMI_KCS_OBF_MASK (1 << IPMI_KCS_OBF_BIT) 36 #define IPMI_KCS_GET_OBF(d) (((d) >> IPMI_KCS_OBF_BIT) & 0x1) 37 #define IPMI_KCS_SET_OBF(d, v) (d) = (((d) & ~IPMI_KCS_OBF_MASK) | \ 38 (((v) & 1) << IPMI_KCS_OBF_BIT)) 39 #define IPMI_KCS_IBF_MASK (1 << IPMI_KCS_IBF_BIT) 40 #define IPMI_KCS_GET_IBF(d) (((d) >> IPMI_KCS_IBF_BIT) & 0x1) 41 #define IPMI_KCS_SET_IBF(d, v) (d) = (((d) & ~IPMI_KCS_IBF_MASK) | \ 42 (((v) & 1) << IPMI_KCS_IBF_BIT)) 43 #define IPMI_KCS_SMS_ATN_MASK (1 << IPMI_KCS_SMS_ATN_BIT) 44 #define IPMI_KCS_GET_SMS_ATN(d) (((d) >> IPMI_KCS_SMS_ATN_BIT) & 0x1) 45 #define IPMI_KCS_SET_SMS_ATN(d, v) (d) = (((d) & ~IPMI_KCS_SMS_ATN_MASK) | \ 46 (((v) & 1) << IPMI_KCS_SMS_ATN_BIT)) 47 #define IPMI_KCS_CD_MASK (1 << IPMI_KCS_CD_BIT) 48 #define IPMI_KCS_GET_CD(d) (((d) >> IPMI_KCS_CD_BIT) & 0x1) 49 #define IPMI_KCS_SET_CD(d, v) (d) = (((d) & ~IPMI_KCS_CD_MASK) | \ 50 (((v) & 1) << IPMI_KCS_CD_BIT)) 51 52 #define IPMI_KCS_IDLE_STATE 0 53 #define IPMI_KCS_READ_STATE 1 54 #define IPMI_KCS_WRITE_STATE 2 55 #define IPMI_KCS_ERROR_STATE 3 56 57 #define IPMI_KCS_GET_STATE(d) (((d) >> 6) & 0x3) 58 #define IPMI_KCS_SET_STATE(d, v) ((d) = ((d) & ~0xc0) | (((v) & 0x3) << 6)) 59 60 #define IPMI_KCS_ABORT_STATUS_CMD 0x60 61 #define IPMI_KCS_WRITE_START_CMD 0x61 62 #define IPMI_KCS_WRITE_END_CMD 0x62 63 #define IPMI_KCS_READ_CMD 0x68 64 65 #define IPMI_KCS_STATUS_NO_ERR 0x00 66 #define IPMI_KCS_STATUS_ABORTED_ERR 0x01 67 #define IPMI_KCS_STATUS_BAD_CC_ERR 0x02 68 #define IPMI_KCS_STATUS_LENGTH_ERR 0x06 69 70 static void ipmi_kcs_raise_irq(IPMIKCS *ik) 71 { 72 if (ik->use_irq && ik->irqs_enabled && ik->raise_irq) { 73 ik->raise_irq(ik); 74 } 75 } 76 77 static void ipmi_kcs_lower_irq(IPMIKCS *ik) 78 { 79 if (ik->lower_irq) { 80 ik->lower_irq(ik); 81 } 82 } 83 84 #define SET_OBF() \ 85 do { \ 86 IPMI_KCS_SET_OBF(ik->status_reg, 1); \ 87 if (!ik->obf_irq_set) { \ 88 ik->obf_irq_set = 1; \ 89 if (!ik->atn_irq_set) { \ 90 ipmi_kcs_raise_irq(ik); \ 91 } \ 92 } \ 93 } while (0) 94 95 static void ipmi_kcs_signal(IPMIKCS *ik, IPMIInterface *ii) 96 { 97 IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii); 98 99 ik->do_wake = 1; 100 while (ik->do_wake) { 101 ik->do_wake = 0; 102 iic->handle_if_event(ii); 103 } 104 } 105 106 static void ipmi_kcs_handle_event(IPMIInterface *ii) 107 { 108 IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii); 109 IPMIKCS *ik = iic->get_backend_data(ii); 110 111 if (ik->cmd_reg == IPMI_KCS_ABORT_STATUS_CMD) { 112 if (IPMI_KCS_GET_STATE(ik->status_reg) != IPMI_KCS_ERROR_STATE) { 113 ik->waiting_rsp++; /* Invalidate the message */ 114 ik->outmsg[0] = IPMI_KCS_STATUS_ABORTED_ERR; 115 ik->outlen = 1; 116 ik->outpos = 0; 117 IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_ERROR_STATE); 118 SET_OBF(); 119 } 120 goto out; 121 } 122 123 switch (IPMI_KCS_GET_STATE(ik->status_reg)) { 124 case IPMI_KCS_IDLE_STATE: 125 if (ik->cmd_reg == IPMI_KCS_WRITE_START_CMD) { 126 IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_WRITE_STATE); 127 ik->cmd_reg = -1; 128 ik->write_end = 0; 129 ik->inlen = 0; 130 SET_OBF(); 131 } 132 break; 133 134 case IPMI_KCS_READ_STATE: 135 handle_read: 136 if (ik->outpos >= ik->outlen) { 137 IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_IDLE_STATE); 138 SET_OBF(); 139 } else if (ik->data_in_reg == IPMI_KCS_READ_CMD) { 140 ik->data_out_reg = ik->outmsg[ik->outpos]; 141 ik->outpos++; 142 SET_OBF(); 143 } else { 144 ik->outmsg[0] = IPMI_KCS_STATUS_BAD_CC_ERR; 145 ik->outlen = 1; 146 ik->outpos = 0; 147 IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_ERROR_STATE); 148 SET_OBF(); 149 goto out; 150 } 151 break; 152 153 case IPMI_KCS_WRITE_STATE: 154 if (ik->data_in_reg != -1) { 155 /* 156 * Don't worry about input overrun here, that will be 157 * handled in the BMC. 158 */ 159 if (ik->inlen < sizeof(ik->inmsg)) { 160 ik->inmsg[ik->inlen] = ik->data_in_reg; 161 } 162 ik->inlen++; 163 } 164 if (ik->write_end) { 165 IPMIBmcClass *bk = IPMI_BMC_GET_CLASS(ik->bmc); 166 ik->outlen = 0; 167 ik->write_end = 0; 168 ik->outpos = 0; 169 bk->handle_command(ik->bmc, ik->inmsg, ik->inlen, sizeof(ik->inmsg), 170 ik->waiting_rsp); 171 goto out_noibf; 172 } else if (ik->cmd_reg == IPMI_KCS_WRITE_END_CMD) { 173 ik->cmd_reg = -1; 174 ik->write_end = 1; 175 } 176 SET_OBF(); 177 break; 178 179 case IPMI_KCS_ERROR_STATE: 180 if (ik->data_in_reg != -1) { 181 IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_READ_STATE); 182 ik->data_in_reg = IPMI_KCS_READ_CMD; 183 goto handle_read; 184 } 185 break; 186 } 187 188 if (ik->cmd_reg != -1) { 189 /* Got an invalid command */ 190 ik->outmsg[0] = IPMI_KCS_STATUS_BAD_CC_ERR; 191 ik->outlen = 1; 192 ik->outpos = 0; 193 IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_ERROR_STATE); 194 } 195 196 out: 197 ik->cmd_reg = -1; 198 ik->data_in_reg = -1; 199 IPMI_KCS_SET_IBF(ik->status_reg, 0); 200 out_noibf: 201 return; 202 } 203 204 static void ipmi_kcs_handle_rsp(IPMIInterface *ii, uint8_t msg_id, 205 unsigned char *rsp, unsigned int rsp_len) 206 { 207 IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii); 208 IPMIKCS *ik = iic->get_backend_data(ii); 209 210 if (ik->waiting_rsp == msg_id) { 211 ik->waiting_rsp++; 212 if (rsp_len > sizeof(ik->outmsg)) { 213 ik->outmsg[0] = rsp[0]; 214 ik->outmsg[1] = rsp[1]; 215 ik->outmsg[2] = IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES; 216 ik->outlen = 3; 217 } else { 218 memcpy(ik->outmsg, rsp, rsp_len); 219 ik->outlen = rsp_len; 220 } 221 IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_READ_STATE); 222 ik->data_in_reg = IPMI_KCS_READ_CMD; 223 ipmi_kcs_signal(ik, ii); 224 } 225 } 226 227 228 static uint64_t ipmi_kcs_ioport_read(void *opaque, hwaddr addr, unsigned size) 229 { 230 IPMIInterface *ii = opaque; 231 IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii); 232 IPMIKCS *ik = iic->get_backend_data(ii); 233 uint32_t ret; 234 235 switch (addr & 1) { 236 case 0: 237 ret = ik->data_out_reg; 238 IPMI_KCS_SET_OBF(ik->status_reg, 0); 239 if (ik->obf_irq_set) { 240 ik->obf_irq_set = 0; 241 if (!ik->atn_irq_set) { 242 ipmi_kcs_lower_irq(ik); 243 } 244 } 245 break; 246 case 1: 247 ret = ik->status_reg; 248 if (ik->atn_irq_set) { 249 ik->atn_irq_set = 0; 250 if (!ik->obf_irq_set) { 251 ipmi_kcs_lower_irq(ik); 252 } 253 } 254 break; 255 } 256 return ret; 257 } 258 259 static void ipmi_kcs_ioport_write(void *opaque, hwaddr addr, uint64_t val, 260 unsigned size) 261 { 262 IPMIInterface *ii = opaque; 263 IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii); 264 IPMIKCS *ik = iic->get_backend_data(ii); 265 266 if (IPMI_KCS_GET_IBF(ik->status_reg)) { 267 return; 268 } 269 270 switch (addr & 1) { 271 case 0: 272 ik->data_in_reg = val; 273 break; 274 275 case 1: 276 ik->cmd_reg = val; 277 break; 278 } 279 IPMI_KCS_SET_IBF(ik->status_reg, 1); 280 ipmi_kcs_signal(ik, ii); 281 } 282 283 const MemoryRegionOps ipmi_kcs_io_ops = { 284 .read = ipmi_kcs_ioport_read, 285 .write = ipmi_kcs_ioport_write, 286 .impl = { 287 .min_access_size = 1, 288 .max_access_size = 1, 289 }, 290 .endianness = DEVICE_LITTLE_ENDIAN, 291 }; 292 293 static void ipmi_kcs_set_atn(IPMIInterface *ii, int val, int irq) 294 { 295 IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii); 296 IPMIKCS *ik = iic->get_backend_data(ii); 297 298 IPMI_KCS_SET_SMS_ATN(ik->status_reg, val); 299 if (val) { 300 if (irq && !ik->atn_irq_set) { 301 ik->atn_irq_set = 1; 302 if (!ik->obf_irq_set) { 303 ipmi_kcs_raise_irq(ik); 304 } 305 } 306 } else { 307 if (ik->atn_irq_set) { 308 ik->atn_irq_set = 0; 309 if (!ik->obf_irq_set) { 310 ipmi_kcs_lower_irq(ik); 311 } 312 } 313 } 314 } 315 316 static void ipmi_kcs_set_irq_enable(IPMIInterface *ii, int val) 317 { 318 IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii); 319 IPMIKCS *ik = iic->get_backend_data(ii); 320 321 ik->irqs_enabled = val; 322 } 323 324 static void ipmi_kcs_init(IPMIInterface *ii, Error **errp) 325 { 326 IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii); 327 IPMIKCS *ik = iic->get_backend_data(ii); 328 329 ik->io_length = 2; 330 memory_region_init_io(&ik->io, NULL, &ipmi_kcs_io_ops, ii, "ipmi-kcs", 2); 331 } 332 333 int ipmi_kcs_vmstate_post_load(void *opaque, int version) 334 { 335 IPMIKCS *ik = opaque; 336 337 /* Make sure all the values are sane. */ 338 if (ik->outpos >= MAX_IPMI_MSG_SIZE || ik->outlen >= MAX_IPMI_MSG_SIZE || 339 ik->outpos >= ik->outlen) { 340 qemu_log_mask(LOG_GUEST_ERROR, 341 "ipmi:kcs: vmstate transfer received bad out values: %d %d\n", 342 ik->outpos, ik->outlen); 343 ik->outpos = 0; 344 ik->outlen = 0; 345 } 346 347 if (ik->inlen >= MAX_IPMI_MSG_SIZE) { 348 qemu_log_mask(LOG_GUEST_ERROR, 349 "ipmi:kcs: vmstate transfer received bad in value: %d\n", 350 ik->inlen); 351 ik->inlen = 0; 352 } 353 354 return 0; 355 } 356 357 static bool vmstate_kcs_before_version2(void *opaque, int version) 358 { 359 return version <= 1; 360 } 361 362 const VMStateDescription vmstate_IPMIKCS = { 363 .name = TYPE_IPMI_INTERFACE_PREFIX "kcs", 364 .version_id = 2, 365 .minimum_version_id = 1, 366 .post_load = ipmi_kcs_vmstate_post_load, 367 .fields = (VMStateField[]) { 368 VMSTATE_BOOL(obf_irq_set, IPMIKCS), 369 VMSTATE_BOOL(atn_irq_set, IPMIKCS), 370 VMSTATE_UNUSED_TEST(vmstate_kcs_before_version2, 1), /* Was use_irq */ 371 VMSTATE_BOOL(irqs_enabled, IPMIKCS), 372 VMSTATE_UINT32(outpos, IPMIKCS), 373 VMSTATE_UINT32_V(outlen, IPMIKCS, 2), 374 VMSTATE_UINT8_ARRAY(outmsg, IPMIKCS, MAX_IPMI_MSG_SIZE), 375 VMSTATE_UINT32_V(inlen, IPMIKCS, 2), 376 VMSTATE_UINT8_ARRAY(inmsg, IPMIKCS, MAX_IPMI_MSG_SIZE), 377 VMSTATE_BOOL(write_end, IPMIKCS), 378 VMSTATE_UINT8(status_reg, IPMIKCS), 379 VMSTATE_UINT8(data_out_reg, IPMIKCS), 380 VMSTATE_INT16(data_in_reg, IPMIKCS), 381 VMSTATE_INT16(cmd_reg, IPMIKCS), 382 VMSTATE_UINT8(waiting_rsp, IPMIKCS), 383 VMSTATE_END_OF_LIST() 384 } 385 }; 386 387 void ipmi_kcs_get_fwinfo(IPMIKCS *ik, IPMIFwInfo *info) 388 { 389 info->interface_name = "kcs"; 390 info->interface_type = IPMI_SMBIOS_KCS; 391 info->ipmi_spec_major_revision = 2; 392 info->ipmi_spec_minor_revision = 0; 393 info->base_address = ik->io_base; 394 info->i2c_slave_address = ik->bmc->slave_addr; 395 info->register_length = ik->io_length; 396 info->register_spacing = 1; 397 info->memspace = IPMI_MEMSPACE_IO; 398 info->irq_type = IPMI_LEVEL_IRQ; 399 } 400 401 void ipmi_kcs_class_init(IPMIInterfaceClass *iic) 402 { 403 iic->init = ipmi_kcs_init; 404 iic->set_atn = ipmi_kcs_set_atn; 405 iic->handle_rsp = ipmi_kcs_handle_rsp; 406 iic->handle_if_event = ipmi_kcs_handle_event; 407 iic->set_irq_enable = ipmi_kcs_set_irq_enable; 408 } 409