From patchwork Tue Apr 7 19:51:30 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Corey Minyard X-Patchwork-Id: 458766 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id C61F2140213 for ; Wed, 8 Apr 2015 05:52:41 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=fail reason="verification failed; unprotected key" header.d=gmail.com header.i=@gmail.com header.b=ezkZPAtn; dkim-adsp=none (unprotected policy); dkim-atps=neutral Received: from localhost ([::1]:48558 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YfZY7-0002uk-Vn for incoming@patchwork.ozlabs.org; Tue, 07 Apr 2015 15:52:40 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:60591) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YfZXR-0001ZS-0O for qemu-devel@nongnu.org; Tue, 07 Apr 2015 15:51:59 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YfZXO-0002Cx-LQ for qemu-devel@nongnu.org; Tue, 07 Apr 2015 15:51:56 -0400 Received: from mail-ob0-x22e.google.com ([2607:f8b0:4003:c01::22e]:35747) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YfZXN-0002Cj-Um for qemu-devel@nongnu.org; Tue, 07 Apr 2015 15:51:54 -0400 Received: by obbfy7 with SMTP id fy7so106886793obb.2 for ; Tue, 07 Apr 2015 12:51:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=nLeVzdVFpt8ds6dIE5cmzZwigOElvMYiZmeS9a4kqi8=; b=ezkZPAtnAk3hZ17F4cucffhJWf7K4a3Qzn2c/f0iRRHqx0ygv0rEAp0TZLeE6ucvSV +IPQGjFM1ef2J+QsOnKFVrSIVmCyKUWIXX+p9QKkqY4v8fGKxcQst740ULXfVYnPmrp4 Pio/sm/SGG8IG9HGXfM3vs0uHtRITexhyfCqda1y3GRxiL27mChuunaSC68AJNUPvG12 31IpMnc/lR1BQDt0/MsgedOfGyG4HDG5lsZJ18C6+G+tlLoGmDHxq2uzujdNbYHFMIK9 90jhfA8RAW0d2z8hsy2BVfGMTqu5fa6hwzaOLzV+NxndjCn6rvsC82aGy8Nz3iI1kX6S 7tZg== X-Received: by 10.182.87.8 with SMTP id t8mr27650216obz.35.1428436313353; Tue, 07 Apr 2015 12:51:53 -0700 (PDT) Received: from t430.minyard.home (pool-173-57-158-30.dllstx.fios.verizon.net. [173.57.158.30]) by mx.google.com with ESMTPSA id ud2sm6983163oeb.12.2015.04.07.12.51.50 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 07 Apr 2015 12:51:51 -0700 (PDT) Received: from t430.minyard.home (t430.minyard.home [127.0.0.1]) by t430.minyard.home (8.14.7/8.14.7) with ESMTP id t37JpnTg024647; Tue, 7 Apr 2015 14:51:49 -0500 Received: (from cminyard@localhost) by t430.minyard.home (8.14.7/8.14.7/Submit) id t37JpndD024645; Tue, 7 Apr 2015 14:51:49 -0500 From: minyard@acm.org To: qemu-devel@nongnu.org Date: Tue, 7 Apr 2015 14:51:30 -0500 Message-Id: <1428436304-24044-2-git-send-email-minyard@acm.org> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1428436304-24044-1-git-send-email-minyard@acm.org> References: <1428436304-24044-1-git-send-email-minyard@acm.org> X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2607:f8b0:4003:c01::22e Cc: Corey Minyard Subject: [Qemu-devel] [PATCH 01/15] Add a base IPMI interface X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: Corey Minyard Add the basic IPMI types and infrastructure to QEMU. Low-level interfaces and simulation interfaces will register with this; it's kind of the go-between to tie them together. Signed-off-by: Corey Minyard --- default-configs/i386-softmmu.mak | 1 + default-configs/x86_64-softmmu.mak | 1 + hw/Makefile.objs | 1 + hw/ipmi/Makefile.objs | 1 + hw/ipmi/ipmi.c | 135 +++++++++++++++++++++++ hw/ipmi/ipmi.h | 215 +++++++++++++++++++++++++++++++++++++ qemu-doc.texi | 2 + 7 files changed, 356 insertions(+) create mode 100644 hw/ipmi/Makefile.objs create mode 100644 hw/ipmi/ipmi.c create mode 100644 hw/ipmi/ipmi.h diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak index 6a74e00..ab1a552 100644 --- a/default-configs/i386-softmmu.mak +++ b/default-configs/i386-softmmu.mak @@ -8,6 +8,7 @@ CONFIG_VGA_ISA=y CONFIG_VGA_CIRRUS=y CONFIG_VMWARE_VGA=y CONFIG_VMMOUSE=y +CONFIG_IPMI=y CONFIG_SERIAL=y CONFIG_PARALLEL=y CONFIG_I8254=y diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak index 46b87dd..82bafcc 100644 --- a/default-configs/x86_64-softmmu.mak +++ b/default-configs/x86_64-softmmu.mak @@ -8,6 +8,7 @@ CONFIG_VGA_ISA=y CONFIG_VGA_CIRRUS=y CONFIG_VMWARE_VGA=y CONFIG_VMMOUSE=y +CONFIG_IPMI=y CONFIG_SERIAL=y CONFIG_PARALLEL=y CONFIG_I8254=y diff --git a/hw/Makefile.objs b/hw/Makefile.objs index 73afa41..ba021b8 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -13,6 +13,7 @@ devices-dirs-$(CONFIG_SOFTMMU) += ide/ devices-dirs-$(CONFIG_SOFTMMU) += input/ devices-dirs-$(CONFIG_SOFTMMU) += intc/ devices-dirs-$(CONFIG_IPACK) += ipack/ +devices-dirs-$(CONFIG_SOFTMMU) += ipmi/ devices-dirs-$(CONFIG_SOFTMMU) += isa/ devices-dirs-$(CONFIG_SOFTMMU) += misc/ devices-dirs-$(CONFIG_SOFTMMU) += net/ diff --git a/hw/ipmi/Makefile.objs b/hw/ipmi/Makefile.objs new file mode 100644 index 0000000..65bde11 --- /dev/null +++ b/hw/ipmi/Makefile.objs @@ -0,0 +1 @@ +common-obj-$(CONFIG_IPMI) += ipmi.o diff --git a/hw/ipmi/ipmi.c b/hw/ipmi/ipmi.c new file mode 100644 index 0000000..b046517 --- /dev/null +++ b/hw/ipmi/ipmi.c @@ -0,0 +1,135 @@ +/* + * QEMU IPMI emulation + * + * Copyright (c) 2012 Corey Minyard, MontaVista Software, LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "hw/hw.h" +#include "ipmi.h" +#include "sysemu/sysemu.h" +#include "qmp-commands.h" + +static int ipmi_do_hw_op(IPMIInterface *s, enum ipmi_op op, int checkonly) +{ + switch (op) { + case IPMI_RESET_CHASSIS: + if (checkonly) { + return 0; + } + qemu_system_reset_request(); + return 0; + + case IPMI_POWEROFF_CHASSIS: + if (checkonly) { + return 0; + } + qemu_system_powerdown_request(); + return 0; + + case IPMI_SEND_NMI: + if (checkonly) { + return 0; + } + qemu_mutex_lock_iothread(); + qmp_inject_nmi(NULL); + qemu_mutex_unlock_iothread(); + return 0; + + case IPMI_POWERCYCLE_CHASSIS: + case IPMI_PULSE_DIAG_IRQ: + case IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP: + case IPMI_POWERON_CHASSIS: + default: + return IPMI_CC_COMMAND_NOT_SUPPORTED; + } +} + +static void ipmi_set_irq_enable(IPMIInterface *s, int val) +{ + s->irqs_enabled = val; +} + +void ipmi_interface_reset(IPMIInterface *s) +{ + IPMIBmcClass *bk = IPMI_BMC_GET_CLASS(s->bmc); + + if (bk->handle_reset) { + bk->handle_reset(s->bmc); + } +} + +void ipmi_interface_init(IPMIInterface *s, Error **errp) +{ + IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); + + if (k->init) { + k->init(s, errp); + if (*errp) { + return; + } + } + + if (!s->slave_addr) { + s->slave_addr = 0x20; + } +} + +static void ipmi_interface_class_init(ObjectClass *class, void *data) +{ + IPMIInterfaceClass *ik = IPMI_INTERFACE_CLASS(class); + + ik->do_hw_op = ipmi_do_hw_op; + ik->set_irq_enable = ipmi_set_irq_enable; +} + +static TypeInfo ipmi_interface_type_info = { + .name = TYPE_IPMI_INTERFACE, + .parent = TYPE_OBJECT, + .instance_size = sizeof(IPMIInterface), + .abstract = true, + .class_size = sizeof(IPMIInterfaceClass), + .class_init = ipmi_interface_class_init, +}; + +void ipmi_bmc_init(IPMIBmc *s, Error **errp) +{ + IPMIBmcClass *k = IPMI_BMC_GET_CLASS(s); + + if (k->init) { + k->init(s, errp); + } +} + +static TypeInfo ipmi_bmc_type_info = { + .name = TYPE_IPMI_BMC, + .parent = TYPE_OBJECT, + .instance_size = sizeof(IPMIBmc), + .abstract = true, + .class_size = sizeof(IPMIBmcClass), +}; + +static void ipmi_register_types(void) +{ + type_register_static(&ipmi_interface_type_info); + type_register_static(&ipmi_bmc_type_info); +} + +type_init(ipmi_register_types) diff --git a/hw/ipmi/ipmi.h b/hw/ipmi/ipmi.h new file mode 100644 index 0000000..6b2a3e9 --- /dev/null +++ b/hw/ipmi/ipmi.h @@ -0,0 +1,215 @@ +/* + * IPMI base class + * + * Copyright (c) 2012 Corey Minyard, MontaVista Software, LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef HW_IPMI_H +#define HW_IPMI_H + +#include "exec/memory.h" +#include "qemu-common.h" +#include "hw/qdev.h" + +#define MAX_IPMI_MSG_SIZE 300 + +enum ipmi_op { + IPMI_RESET_CHASSIS, + IPMI_POWEROFF_CHASSIS, + IPMI_POWERON_CHASSIS, + IPMI_POWERCYCLE_CHASSIS, + IPMI_PULSE_DIAG_IRQ, + IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, + IPMI_SEND_NMI +}; + +#define IPMI_CC_INVALID_CMD 0xc1 +#define IPMI_CC_COMMAND_INVALID_FOR_LUN 0xc2 +#define IPMI_CC_TIMEOUT 0xc3 +#define IPMI_CC_OUT_OF_SPACE 0xc4 +#define IPMI_CC_INVALID_RESERVATION 0xc5 +#define IPMI_CC_REQUEST_DATA_TRUNCATED 0xc6 +#define IPMI_CC_REQUEST_DATA_LENGTH_INVALID 0xc7 +#define IPMI_CC_PARM_OUT_OF_RANGE 0xc9 +#define IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES 0xca +#define IPMI_CC_REQ_ENTRY_NOT_PRESENT 0xcb +#define IPMI_CC_INVALID_DATA_FIELD 0xcc +#define IPMI_CC_BMC_INIT_IN_PROGRESS 0xd2 +#define IPMI_CC_COMMAND_NOT_SUPPORTED 0xd5 + +#define IPMI_NETFN_APP 0x06 + +#define IPMI_DEBUG 1 + +/* Specified in the SMBIOS spec. */ +#define IPMI_SMBIOS_KCS 0x01 +#define IPMI_SMBIOS_SMIC 0x02 +#define IPMI_SMBIOS_BT 0x03 +#define IPMI_SMBIOS_SSIF 0x04 + +/* IPMI Interface types (KCS, SMIC, BT) are prefixed with this */ +#define TYPE_IPMI_INTERFACE_PREFIX "ipmi-interface-" + +typedef struct IPMIBmc IPMIBmc; + +/* + * An IPMI Interface, the interface for talking between the target + * and the BMC. + */ +#define TYPE_IPMI_INTERFACE "ipmi-interface" +#define IPMI_INTERFACE(obj) \ + OBJECT_CHECK(IPMIInterface, (obj), TYPE_IPMI_INTERFACE) +#define IPMI_INTERFACE_CLASS(klass) \ + OBJECT_CLASS_CHECK(IPMIInterfaceClass, (klass), TYPE_IPMI_INTERFACE) +#define IPMI_INTERFACE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(IPMIInterfaceClass, (obj), TYPE_IPMI_INTERFACE) + +typedef struct IPMIInterface { + Object parent_obj; + + IPMIBmc *bmc; + + bool do_wake; + + qemu_irq irq; + + unsigned long io_base; + unsigned long io_length; + MemoryRegion io; + + unsigned char slave_addr; + + bool obf_irq_set; + bool atn_irq_set; + bool use_irq; + bool irqs_enabled; + + uint8_t outmsg[MAX_IPMI_MSG_SIZE]; + uint32_t outpos; + uint32_t outlen; + + uint8_t inmsg[MAX_IPMI_MSG_SIZE]; + uint32_t inlen; + bool write_end; +} IPMIInterface; + +typedef struct IPMIInterfaceClass { + ObjectClass parent_class; + + unsigned int smbios_type; + + void (*init)(struct IPMIInterface *s, Error **errp); + + /* + * Perform various operations on the hardware. If checkonly is + * true, it will return if the operation can be performed, but it + * will not do the operation. + */ + int (*do_hw_op)(struct IPMIInterface *s, enum ipmi_op op, int checkonly); + + /* + * Enable/disable irqs on the interface when the BMC requests this. + */ + void (*set_irq_enable)(struct IPMIInterface *s, int val); + + /* + * Handle an event that occurred on the interface, generally the. + * target writing to a register. + */ + void (*handle_if_event)(struct IPMIInterface *s); + + /* + * The interfaces use this to perform certain ops + */ + void (*set_atn)(struct IPMIInterface *s, int val, int irq); + + /* + * Got an IPMI warm/cold reset. + */ + void (*reset)(struct IPMIInterface *s, bool is_cold); + + /* + * Handle a response from the bmc. + */ + void (*handle_rsp)(struct IPMIInterface *s, uint8_t msg_id, + unsigned char *rsp, unsigned int rsp_len); +} IPMIInterfaceClass; + +void ipmi_interface_init(IPMIInterface *s, Error **errp); +void ipmi_interface_reset(IPMIInterface *s); + +/* + * Define a BMC simulator (or perhaps a connection to a real BMC) + */ +#define TYPE_IPMI_BMC "ipmi-bmc" +#define IPMI_BMC(obj) \ + OBJECT_CHECK(IPMIBmc, (obj), TYPE_IPMI_BMC) +#define IPMI_BMC_CLASS(klass) \ + OBJECT_CLASS_CHECK(IPMIBmcClass, (klass), TYPE_IPMI_BMC) +#define IPMI_BMC_GET_CLASS(obj) \ + OBJECT_GET_CLASS(IPMIBmcClass, (obj), TYPE_IPMI_BMC) + +#define TYPE_IPMI_BMC_EXTERN "ipmi-bmc-extern" +#define TYPE_IPMI_BMC_SIMULATOR "ipmi-bmc-sim" + +static inline void ipmi_signal(IPMIInterface *s) +{ + s->do_wake = 1; + while (s->do_wake) { + s->do_wake = 0; + (IPMI_INTERFACE_GET_CLASS(s))->handle_if_event(s); + } +} + +struct IPMIBmc { + Object parent_obj; + + IPMIInterface *intf; + CharDriverState *chr; +}; + +typedef struct IPMIBmcClass { + ObjectClass parent_class; + + void (*init)(IPMIBmc *s, Error **errp); + + /* Called when the system resets to report to the bmc. */ + void (*handle_reset)(struct IPMIBmc *s); + + /* + * Handle a command to the bmc. + */ + void (*handle_command)(struct IPMIBmc *s, + uint8_t *cmd, unsigned int cmd_len, + unsigned int max_cmd_len, + uint8_t msg_id); +} IPMIBmcClass; + +void ipmi_bmc_init(IPMIBmc *s, Error **errp); + +#ifdef IPMI_DEBUG +#define ipmi_debug(fs, ...) \ + fprintf(stderr, "IPMI (%s): " fs, __func__, ##__VA_ARGS__) +#else +#define ipmi_debug(fs, ...) +#endif + +#endif diff --git a/qemu-doc.texi b/qemu-doc.texi index 0125bc7..80a22a4 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -195,6 +195,8 @@ PCI and ISA network adapters @item Serial ports @item +IPMI BMC, either and internal or external one +@item Creative SoundBlaster 16 sound card @item ENSONIQ AudioPCI ES1370 sound card