From: Corey Minyard <cminyard@mvista.com>
The vmstate for isa_ipmi_kcs was referencing into the kcs structure,
instead create a kcs structure separate and use that.
There were also some issues in the state transfer. The inlen field
was not being transferred, so if a transaction was in process during
the transfer it would be messed up. And the use_irq field was
transferred, but that should come from the configuration.
To fix this, the new VMS_VSTRUCT macros are used so the exact
version of the structure can be specified, depending on what
version was being received. So an upgrade should work for KCS.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
Cc: Dr. David Alan Gilbert <dgilbert@redhat.com>
---
hw/ipmi/isa_ipmi_kcs.c | 81 ++++++++++++++++++++++++++++++++++++++++----------
1 file changed, 66 insertions(+), 15 deletions(-)
diff --git a/hw/ipmi/isa_ipmi_kcs.c b/hw/ipmi/isa_ipmi_kcs.c
index 689587b..a794315 100644
--- a/hw/ipmi/isa_ipmi_kcs.c
+++ b/hw/ipmi/isa_ipmi_kcs.c
@@ -22,6 +22,7 @@
* THE SOFTWARE.
*/
#include "qemu/osdep.h"
+#include "qemu/log.h"
#include "qapi/error.h"
#include "hw/hw.h"
#include "hw/ipmi/ipmi.h"
@@ -422,24 +423,69 @@ static void ipmi_isa_realize(DeviceState *dev, Error **errp)
isa_register_ioport(isadev, &iik->kcs.io, iik->kcs.io_base);
}
-const VMStateDescription vmstate_ISAIPMIKCSDevice = {
+static int ipmi_kcs_vmstate_post_load(void *opaque, int version)
+{
+ IPMIKCS *ik = opaque;
+
+ /* Make sure all the values are sane. */
+ if (ik->outpos >= MAX_IPMI_MSG_SIZE || ik->outlen >= MAX_IPMI_MSG_SIZE ||
+ ik->outpos >= ik->outlen) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "ipmi:kcs: vmstate transfer received bad out values: %d %d\n",
+ ik->outpos, ik->outlen);
+ ik->outpos = 0;
+ ik->outlen = 0;
+ }
+
+ if (ik->inlen >= MAX_IPMI_MSG_SIZE) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "ipmi:kcs: vmstate transfer received bad in value: %d\n",
+ ik->inlen);
+ ik->inlen = 0;
+ }
+
+ return 0;
+}
+
+static bool vmstate_kcs_before_version2(void *opaque, int version)
+{
+ return version <= 1;
+}
+
+static const VMStateDescription vmstate_IPMIKCS = {
+ .name = TYPE_IPMI_INTERFACE_PREFIX "kcs",
+ .version_id = 2,
+ .minimum_version_id = 1,
+ .post_load = ipmi_kcs_vmstate_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_BOOL(obf_irq_set, IPMIKCS),
+ VMSTATE_BOOL(atn_irq_set, IPMIKCS),
+ VMSTATE_UNUSED_TEST(vmstate_kcs_before_version2, 1), /* Was use_irq */
+ VMSTATE_BOOL(irqs_enabled, IPMIKCS),
+ VMSTATE_UINT32(outpos, IPMIKCS),
+ VMSTATE_UINT32_V(outlen, IPMIKCS, 2),
+ VMSTATE_UINT8_ARRAY(outmsg, IPMIKCS, MAX_IPMI_MSG_SIZE),
+ VMSTATE_UINT32_V(inlen, IPMIKCS, 2),
+ VMSTATE_UINT8_ARRAY(inmsg, IPMIKCS, MAX_IPMI_MSG_SIZE),
+ VMSTATE_BOOL(write_end, IPMIKCS),
+ VMSTATE_UINT8(status_reg, IPMIKCS),
+ VMSTATE_UINT8(data_out_reg, IPMIKCS),
+ VMSTATE_INT16(data_in_reg, IPMIKCS),
+ VMSTATE_INT16(cmd_reg, IPMIKCS),
+ VMSTATE_UINT8(waiting_rsp, IPMIKCS),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_ISAIPMIKCSDevice = {
.name = TYPE_IPMI_INTERFACE,
- .version_id = 1,
+ .version_id = 2,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
- VMSTATE_BOOL(kcs.obf_irq_set, ISAIPMIKCSDevice),
- VMSTATE_BOOL(kcs.atn_irq_set, ISAIPMIKCSDevice),
- VMSTATE_BOOL(kcs.use_irq, ISAIPMIKCSDevice),
- VMSTATE_BOOL(kcs.irqs_enabled, ISAIPMIKCSDevice),
- VMSTATE_UINT32(kcs.outpos, ISAIPMIKCSDevice),
- VMSTATE_UINT8_ARRAY(kcs.outmsg, ISAIPMIKCSDevice, MAX_IPMI_MSG_SIZE),
- VMSTATE_UINT8_ARRAY(kcs.inmsg, ISAIPMIKCSDevice, MAX_IPMI_MSG_SIZE),
- VMSTATE_BOOL(kcs.write_end, ISAIPMIKCSDevice),
- VMSTATE_UINT8(kcs.status_reg, ISAIPMIKCSDevice),
- VMSTATE_UINT8(kcs.data_out_reg, ISAIPMIKCSDevice),
- VMSTATE_INT16(kcs.data_in_reg, ISAIPMIKCSDevice),
- VMSTATE_INT16(kcs.cmd_reg, ISAIPMIKCSDevice),
- VMSTATE_UINT8(kcs.waiting_rsp, ISAIPMIKCSDevice),
+ VMSTATE_VSTRUCT_TEST(kcs, ISAIPMIKCSDevice, vmstate_kcs_before_version2,
+ 0, vmstate_IPMIKCS, IPMIKCS, 1),
+ VMSTATE_VSTRUCT_V(kcs, ISAIPMIKCSDevice, 2, vmstate_IPMIKCS,
+ IPMIKCS, 2),
VMSTATE_END_OF_LIST()
}
};
@@ -450,6 +496,11 @@ static void isa_ipmi_kcs_init(Object *obj)
ipmi_bmc_find_and_link(obj, (Object **) &iik->kcs.bmc);
+ /*
+ * Version 1 had an incorrect name, it clashed with the BT
+ * IPMI device, so receive it, but transmit a different
+ * version.
+ */
vmstate_register(NULL, 0, &vmstate_ISAIPMIKCSDevice, iik);
}
--
2.7.4
Hi Corey
On Wed, Apr 25, 2018 at 5:27 PM, <minyard@acm.org> wrote:
> From: Corey Minyard <cminyard@mvista.com>
>
> The vmstate for isa_ipmi_kcs was referencing into the kcs structure,
> instead create a kcs structure separate and use that.
>
> There were also some issues in the state transfer. The inlen field
> was not being transferred, so if a transaction was in process during
> the transfer it would be messed up. And the use_irq field was
> transferred, but that should come from the configuration.
>
> To fix this, the new VMS_VSTRUCT macros are used so the exact
> version of the structure can be specified, depending on what
> version was being received. So an upgrade should work for KCS.
Looks good overall,
You could easily split this patch further to help review/bisecting etc.
Introduce VMSTATE_STRUCT, unuse use_irq, introduce version 2, add the
postload checks.
You could also help reviewers by giving your test setup, so we can
more easily reproduce the fix and/or try variants.
I also wonder if you could have used subsections, but the VSTRUCT type
seems a good approach to me, David would have to review it though.
> Signed-off-by: Corey Minyard <cminyard@mvista.com>
> Cc: Dr. David Alan Gilbert <dgilbert@redhat.com>
> ---
> hw/ipmi/isa_ipmi_kcs.c | 81 ++++++++++++++++++++++++++++++++++++++++----------
> 1 file changed, 66 insertions(+), 15 deletions(-)
>
> diff --git a/hw/ipmi/isa_ipmi_kcs.c b/hw/ipmi/isa_ipmi_kcs.c
> index 689587b..a794315 100644
> --- a/hw/ipmi/isa_ipmi_kcs.c
> +++ b/hw/ipmi/isa_ipmi_kcs.c
> @@ -22,6 +22,7 @@
> * THE SOFTWARE.
> */
> #include "qemu/osdep.h"
> +#include "qemu/log.h"
> #include "qapi/error.h"
> #include "hw/hw.h"
> #include "hw/ipmi/ipmi.h"
> @@ -422,24 +423,69 @@ static void ipmi_isa_realize(DeviceState *dev, Error **errp)
> isa_register_ioport(isadev, &iik->kcs.io, iik->kcs.io_base);
> }
>
> -const VMStateDescription vmstate_ISAIPMIKCSDevice = {
> +static int ipmi_kcs_vmstate_post_load(void *opaque, int version)
> +{
> + IPMIKCS *ik = opaque;
> +
> + /* Make sure all the values are sane. */
> + if (ik->outpos >= MAX_IPMI_MSG_SIZE || ik->outlen >= MAX_IPMI_MSG_SIZE ||
> + ik->outpos >= ik->outlen) {
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "ipmi:kcs: vmstate transfer received bad out values: %d %d\n",
> + ik->outpos, ik->outlen);
> + ik->outpos = 0;
> + ik->outlen = 0;
> + }
> +
> + if (ik->inlen >= MAX_IPMI_MSG_SIZE) {
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "ipmi:kcs: vmstate transfer received bad in value: %d\n",
> + ik->inlen);
> + ik->inlen = 0;
> + }
> +
> + return 0;
> +}
> +
> +static bool vmstate_kcs_before_version2(void *opaque, int version)
> +{
> + return version <= 1;
> +}
> +
> +static const VMStateDescription vmstate_IPMIKCS = {
> + .name = TYPE_IPMI_INTERFACE_PREFIX "kcs",
> + .version_id = 2,
> + .minimum_version_id = 1,
> + .post_load = ipmi_kcs_vmstate_post_load,
> + .fields = (VMStateField[]) {
> + VMSTATE_BOOL(obf_irq_set, IPMIKCS),
> + VMSTATE_BOOL(atn_irq_set, IPMIKCS),
> + VMSTATE_UNUSED_TEST(vmstate_kcs_before_version2, 1), /* Was use_irq */
> + VMSTATE_BOOL(irqs_enabled, IPMIKCS),
> + VMSTATE_UINT32(outpos, IPMIKCS),
> + VMSTATE_UINT32_V(outlen, IPMIKCS, 2),
> + VMSTATE_UINT8_ARRAY(outmsg, IPMIKCS, MAX_IPMI_MSG_SIZE),
> + VMSTATE_UINT32_V(inlen, IPMIKCS, 2),
> + VMSTATE_UINT8_ARRAY(inmsg, IPMIKCS, MAX_IPMI_MSG_SIZE),
> + VMSTATE_BOOL(write_end, IPMIKCS),
> + VMSTATE_UINT8(status_reg, IPMIKCS),
> + VMSTATE_UINT8(data_out_reg, IPMIKCS),
> + VMSTATE_INT16(data_in_reg, IPMIKCS),
> + VMSTATE_INT16(cmd_reg, IPMIKCS),
> + VMSTATE_UINT8(waiting_rsp, IPMIKCS),
> + VMSTATE_END_OF_LIST()
> + }
> +};
> +
> +static const VMStateDescription vmstate_ISAIPMIKCSDevice = {
> .name = TYPE_IPMI_INTERFACE,
> - .version_id = 1,
> + .version_id = 2,
> .minimum_version_id = 1,
> .fields = (VMStateField[]) {
> - VMSTATE_BOOL(kcs.obf_irq_set, ISAIPMIKCSDevice),
> - VMSTATE_BOOL(kcs.atn_irq_set, ISAIPMIKCSDevice),
> - VMSTATE_BOOL(kcs.use_irq, ISAIPMIKCSDevice),
> - VMSTATE_BOOL(kcs.irqs_enabled, ISAIPMIKCSDevice),
> - VMSTATE_UINT32(kcs.outpos, ISAIPMIKCSDevice),
> - VMSTATE_UINT8_ARRAY(kcs.outmsg, ISAIPMIKCSDevice, MAX_IPMI_MSG_SIZE),
> - VMSTATE_UINT8_ARRAY(kcs.inmsg, ISAIPMIKCSDevice, MAX_IPMI_MSG_SIZE),
> - VMSTATE_BOOL(kcs.write_end, ISAIPMIKCSDevice),
> - VMSTATE_UINT8(kcs.status_reg, ISAIPMIKCSDevice),
> - VMSTATE_UINT8(kcs.data_out_reg, ISAIPMIKCSDevice),
> - VMSTATE_INT16(kcs.data_in_reg, ISAIPMIKCSDevice),
> - VMSTATE_INT16(kcs.cmd_reg, ISAIPMIKCSDevice),
> - VMSTATE_UINT8(kcs.waiting_rsp, ISAIPMIKCSDevice),
> + VMSTATE_VSTRUCT_TEST(kcs, ISAIPMIKCSDevice, vmstate_kcs_before_version2,
> + 0, vmstate_IPMIKCS, IPMIKCS, 1),
> + VMSTATE_VSTRUCT_V(kcs, ISAIPMIKCSDevice, 2, vmstate_IPMIKCS,
> + IPMIKCS, 2),
> VMSTATE_END_OF_LIST()
> }
> };
> @@ -450,6 +496,11 @@ static void isa_ipmi_kcs_init(Object *obj)
>
> ipmi_bmc_find_and_link(obj, (Object **) &iik->kcs.bmc);
>
> + /*
> + * Version 1 had an incorrect name, it clashed with the BT
> + * IPMI device, so receive it, but transmit a different
> + * version.
> + */
> vmstate_register(NULL, 0, &vmstate_ISAIPMIKCSDevice, iik);
> }
>
> --
> 2.7.4
>
>
--
Marc-André Lureau
On 05/18/2018 10:45 AM, Marc-André Lureau wrote:
> Hi Corey
>
> On Wed, Apr 25, 2018 at 5:27 PM, <minyard@acm.org> wrote:
>> From: Corey Minyard <cminyard@mvista.com>
>>
>> The vmstate for isa_ipmi_kcs was referencing into the kcs structure,
>> instead create a kcs structure separate and use that.
>>
>> There were also some issues in the state transfer. The inlen field
>> was not being transferred, so if a transaction was in process during
>> the transfer it would be messed up. And the use_irq field was
>> transferred, but that should come from the configuration.
>>
>> To fix this, the new VMS_VSTRUCT macros are used so the exact
>> version of the structure can be specified, depending on what
>> version was being received. So an upgrade should work for KCS.
> Looks good overall,
>
> You could easily split this patch further to help review/bisecting etc.
>
> Introduce VMSTATE_STRUCT, unuse use_irq, introduce version 2, add the
> postload checks.
That's probably fair. I'll do that for v4.
> You could also help reviewers by giving your test setup, so we can
> more easily reproduce the fix and/or try variants.
Hmm. That's a little hard. I'll see what I can do. Maybe it's not too
bad,
most distros should have the openipmi library available.
>
> I also wonder if you could have used subsections, but the VSTRUCT type
> seems a good approach to me, David would have to review it though.
Yeah, I think we talked about subsections at one point, but this seemed
better.
That will have to wait for David.
Thanks,
-corey
>
>> Signed-off-by: Corey Minyard <cminyard@mvista.com>
>> Cc: Dr. David Alan Gilbert <dgilbert@redhat.com>
>> ---
>> hw/ipmi/isa_ipmi_kcs.c | 81 ++++++++++++++++++++++++++++++++++++++++----------
>> 1 file changed, 66 insertions(+), 15 deletions(-)
>>
>> diff --git a/hw/ipmi/isa_ipmi_kcs.c b/hw/ipmi/isa_ipmi_kcs.c
>> index 689587b..a794315 100644
>> --- a/hw/ipmi/isa_ipmi_kcs.c
>> +++ b/hw/ipmi/isa_ipmi_kcs.c
>> @@ -22,6 +22,7 @@
>> * THE SOFTWARE.
>> */
>> #include "qemu/osdep.h"
>> +#include "qemu/log.h"
>> #include "qapi/error.h"
>> #include "hw/hw.h"
>> #include "hw/ipmi/ipmi.h"
>> @@ -422,24 +423,69 @@ static void ipmi_isa_realize(DeviceState *dev, Error **errp)
>> isa_register_ioport(isadev, &iik->kcs.io, iik->kcs.io_base);
>> }
>>
>> -const VMStateDescription vmstate_ISAIPMIKCSDevice = {
>> +static int ipmi_kcs_vmstate_post_load(void *opaque, int version)
>> +{
>> + IPMIKCS *ik = opaque;
>> +
>> + /* Make sure all the values are sane. */
>> + if (ik->outpos >= MAX_IPMI_MSG_SIZE || ik->outlen >= MAX_IPMI_MSG_SIZE ||
>> + ik->outpos >= ik->outlen) {
>> + qemu_log_mask(LOG_GUEST_ERROR,
>> + "ipmi:kcs: vmstate transfer received bad out values: %d %d\n",
>> + ik->outpos, ik->outlen);
>> + ik->outpos = 0;
>> + ik->outlen = 0;
>> + }
>> +
>> + if (ik->inlen >= MAX_IPMI_MSG_SIZE) {
>> + qemu_log_mask(LOG_GUEST_ERROR,
>> + "ipmi:kcs: vmstate transfer received bad in value: %d\n",
>> + ik->inlen);
>> + ik->inlen = 0;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static bool vmstate_kcs_before_version2(void *opaque, int version)
>> +{
>> + return version <= 1;
>> +}
>> +
>> +static const VMStateDescription vmstate_IPMIKCS = {
>> + .name = TYPE_IPMI_INTERFACE_PREFIX "kcs",
>> + .version_id = 2,
>> + .minimum_version_id = 1,
>> + .post_load = ipmi_kcs_vmstate_post_load,
>> + .fields = (VMStateField[]) {
>> + VMSTATE_BOOL(obf_irq_set, IPMIKCS),
>> + VMSTATE_BOOL(atn_irq_set, IPMIKCS),
>> + VMSTATE_UNUSED_TEST(vmstate_kcs_before_version2, 1), /* Was use_irq */
>> + VMSTATE_BOOL(irqs_enabled, IPMIKCS),
>> + VMSTATE_UINT32(outpos, IPMIKCS),
>> + VMSTATE_UINT32_V(outlen, IPMIKCS, 2),
>> + VMSTATE_UINT8_ARRAY(outmsg, IPMIKCS, MAX_IPMI_MSG_SIZE),
>> + VMSTATE_UINT32_V(inlen, IPMIKCS, 2),
>> + VMSTATE_UINT8_ARRAY(inmsg, IPMIKCS, MAX_IPMI_MSG_SIZE),
>> + VMSTATE_BOOL(write_end, IPMIKCS),
>> + VMSTATE_UINT8(status_reg, IPMIKCS),
>> + VMSTATE_UINT8(data_out_reg, IPMIKCS),
>> + VMSTATE_INT16(data_in_reg, IPMIKCS),
>> + VMSTATE_INT16(cmd_reg, IPMIKCS),
>> + VMSTATE_UINT8(waiting_rsp, IPMIKCS),
>> + VMSTATE_END_OF_LIST()
>> + }
>> +};
>> +
>> +static const VMStateDescription vmstate_ISAIPMIKCSDevice = {
>> .name = TYPE_IPMI_INTERFACE,
>> - .version_id = 1,
>> + .version_id = 2,
>> .minimum_version_id = 1,
>> .fields = (VMStateField[]) {
>> - VMSTATE_BOOL(kcs.obf_irq_set, ISAIPMIKCSDevice),
>> - VMSTATE_BOOL(kcs.atn_irq_set, ISAIPMIKCSDevice),
>> - VMSTATE_BOOL(kcs.use_irq, ISAIPMIKCSDevice),
>> - VMSTATE_BOOL(kcs.irqs_enabled, ISAIPMIKCSDevice),
>> - VMSTATE_UINT32(kcs.outpos, ISAIPMIKCSDevice),
>> - VMSTATE_UINT8_ARRAY(kcs.outmsg, ISAIPMIKCSDevice, MAX_IPMI_MSG_SIZE),
>> - VMSTATE_UINT8_ARRAY(kcs.inmsg, ISAIPMIKCSDevice, MAX_IPMI_MSG_SIZE),
>> - VMSTATE_BOOL(kcs.write_end, ISAIPMIKCSDevice),
>> - VMSTATE_UINT8(kcs.status_reg, ISAIPMIKCSDevice),
>> - VMSTATE_UINT8(kcs.data_out_reg, ISAIPMIKCSDevice),
>> - VMSTATE_INT16(kcs.data_in_reg, ISAIPMIKCSDevice),
>> - VMSTATE_INT16(kcs.cmd_reg, ISAIPMIKCSDevice),
>> - VMSTATE_UINT8(kcs.waiting_rsp, ISAIPMIKCSDevice),
>> + VMSTATE_VSTRUCT_TEST(kcs, ISAIPMIKCSDevice, vmstate_kcs_before_version2,
>> + 0, vmstate_IPMIKCS, IPMIKCS, 1),
>> + VMSTATE_VSTRUCT_V(kcs, ISAIPMIKCSDevice, 2, vmstate_IPMIKCS,
>> + IPMIKCS, 2),
>> VMSTATE_END_OF_LIST()
>> }
>> };
>> @@ -450,6 +496,11 @@ static void isa_ipmi_kcs_init(Object *obj)
>>
>> ipmi_bmc_find_and_link(obj, (Object **) &iik->kcs.bmc);
>>
>> + /*
>> + * Version 1 had an incorrect name, it clashed with the BT
>> + * IPMI device, so receive it, but transmit a different
>> + * version.
>> + */
>> vmstate_register(NULL, 0, &vmstate_ISAIPMIKCSDevice, iik);
>> }
>>
>> --
>> 2.7.4
>>
>>
>
>
© 2016 - 2025 Red Hat, Inc.