From: Corey Minyard <cminyard@mvista.com>
To: Bret Ketchum <bcketchum@gmail.com>, Corey Minyard <minyard@acm.org>
Cc: qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [PATCH 11/16] ipmi: Add tests
Date: Wed, 13 Nov 2013 14:51:57 -0600 [thread overview]
Message-ID: <5283E66D.2020304@mvista.com> (raw)
In-Reply-To: <CAGm6yaRrEjv8ROdV2vQHf0EJ-j5w5zv1_QW=62rxzNmhz0i8Sg@mail.gmail.com>
On 11/13/2013 08:12 AM, Bret Ketchum wrote:
> Having trouble with this patch (after the prior patches were
> successfully applied):
I was a couple of days behind and some other changes that came in
conflicted with this.
-corey
>
> git status
> # On branch master
> # Changes not staged for commit:
> # (use "git add <file>..." to update what will be committed)
> # (use "git checkout -- <file>..." to discard changes in working
> directory)
> #
> # modified: ../../../backends/baum.c
> # modified: ../../../backends/msmouse.c
> # modified: ../../../default-configs/i386-softmmu.mak
> # modified: ../../../default-configs/x86_64-softmmu.mak
> # modified: ../../../hw/Makefile.objs
> # modified: ../../../hw/misc/ivshmem.c
> # modified: ../../../include/hw/nvram/fw_cfg.h
> # modified: ../../../include/sysemu/char.h
> # modified: ../../../include/ui/console.h
> # modified: ../../../include/ui/qemu-spice.h
> # modified: ../../../qemu-char.c
> # modified: ../../../qemu-doc.texi
> # modified: ../../../qemu-options.hx
> # modified: ../../../spice-qemu-char.c
> # modified: ../../../ui/console.c
> #
> # Untracked files:
> # (use "git add <file>..." to include in what will be committed)
> #
> # ../../
> # ../../../hw/ipmi/
> no changes added to commit (use "git add" and/or "git commit -a")
> [
>
> git apply --verbos --check ../ipmi-patches/290712.mbox
> Checking patch tests/Makefile...
> error: while searching for:
> gcov-files-i386-y += hw/hd-geometry.c
> check-qtest-i386-y += tests/boot-order-test$(EXESUF)
> check-qtest-i386-y += tests/rtc-test$(EXESUF)
> check-qtest-i386-y += tests/i440fx-test$(EXESUF)
> check-qtest-i386-y += tests/fw_cfg-test$(EXESUF)
> check-qtest-x86_64-y = $(check-qtest-i386-y)
>
> error: patch failed: tests/Makefile:65
> error: tests/Makefile: patch does not apply
> Checking patch tests/ipmi-bt-test.c...
> Checking patch tests/ipmi-kcs-test.c...
>
>
>
> I believe the patch for tests/Makefile should look like:
>
> diff --git a/tests/Makefile b/tests/Makefile
> index f414f2c..0395cd4 100644
> --- a/tests/Makefile
> +++ b/tests/Makefile
> @@ -65,6 +65,8 @@ check-qtest-i386-y += tests/hd-geo-test$(EXESUF)
> gcov-files-i386-y += hw/hd-geometry.c
> check-qtest-i386-y += tests/boot-order-test$(EXESUF)
> check-qtest-i386-y += tests/rtc-test$(EXESUF)
> +check-qtest-i386-y += tests/ipmi-kcs-test$(EXESUF)
> +check-qtest-i386-y += tests/ipmi-bt-test$(EXESUF)
> check-qtest-i386-y += tests/i440fx-test$(EXESUF)
> check-qtest-i386-y += tests/fw_cfg-test$(EXESUF)
> check-qtest-i386-y += tests/qom-test$(EXESUF)
> @@ -194,6 +196,8 @@ tests/m48t59-test$(EXESUF): tests/m48t59-test.o
> tests/endianness-test$(EXESUF): tests/endianness-test.o
> tests/fdc-test$(EXESUF): tests/fdc-test.o
> tests/ide-test$(EXESUF): tests/ide-test.o $(libqos-pc-obj-y)
> +tests/ipmi-kcs-test$(EXESUF): tests/ipmi-kcs-test.o
> +tests/ipmi-bt-test$(EXESUF): tests/ipmi-bt-test.o
> tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o
> tests/boot-order-test$(EXESUF): tests/boot-order-test.o $(libqos-obj-y)
> tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y)
>
>
>
> On Tue, Nov 12, 2013 at 10:33 AM, Corey Minyard <minyard@acm.org
> <mailto:minyard@acm.org>> wrote:
>
> Test the KCS interface with a local BMC and a BT interface with an
> external BMC.
>
> Signed-off-by: Corey Minyard <cminyard@mvista.com
> <mailto:cminyard@mvista.com>>
> ---
> tests/Makefile | 4 +
> tests/ipmi-bt-test.c | 440
> ++++++++++++++++++++++++++++++++++++++++++++++++++
> tests/ipmi-kcs-test.c | 294 +++++++++++++++++++++++++++++++++
> 3 files changed, 738 insertions(+)
> create mode 100644 tests/ipmi-bt-test.c
> create mode 100644 tests/ipmi-kcs-test.c
>
> diff --git a/tests/Makefile b/tests/Makefile
> index fa4c9f0..044e7a8 100644
> --- a/tests/Makefile
> +++ b/tests/Makefile
> @@ -65,6 +65,8 @@ check-qtest-i386-y += tests/hd-geo-test$(EXESUF)
> gcov-files-i386-y += hw/hd-geometry.c
> check-qtest-i386-y += tests/boot-order-test$(EXESUF)
> check-qtest-i386-y += tests/rtc-test$(EXESUF)
> +check-qtest-i386-y += tests/ipmi-kcs-test$(EXESUF)
> +check-qtest-i386-y += tests/ipmi-bt-test$(EXESUF)
> check-qtest-i386-y += tests/i440fx-test$(EXESUF)
> check-qtest-i386-y += tests/fw_cfg-test$(EXESUF)
> check-qtest-x86_64-y = $(check-qtest-i386-y)
> @@ -169,6 +171,8 @@ tests/m48t59-test$(EXESUF): tests/m48t59-test.o
> tests/endianness-test$(EXESUF): tests/endianness-test.o
> tests/fdc-test$(EXESUF): tests/fdc-test.o
> tests/ide-test$(EXESUF): tests/ide-test.o $(libqos-pc-obj-y)
> +tests/ipmi-kcs-test$(EXESUF): tests/ipmi-kcs-test.o
> +tests/ipmi-bt-test$(EXESUF): tests/ipmi-bt-test.o
> tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o
> tests/boot-order-test$(EXESUF): tests/boot-order-test.o
> $(libqos-obj-y)
> tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y)
> diff --git a/tests/ipmi-bt-test.c b/tests/ipmi-bt-test.c
> new file mode 100644
> index 0000000..c1da325
> --- /dev/null
> +++ b/tests/ipmi-bt-test.c
> @@ -0,0 +1,440 @@
> +/*
> + * IPMI BT test cases, using the external interface for checking
> + *
> + * Copyright (c) 2012 Corey Minyard <cminyard@mvista.com
> <mailto:cminyard@mvista.com>>
> + *
> + * 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 <sys/types.h>
> +#include <stdint.h>
> +#include <string.h>
> +#include <stdio.h>
> +
> +#include <sys/socket.h>
> +#include <netinet/in.h>
> +#include <netinet/ip.h>
> +#include <netinet/tcp.h>
> +
> +#include <glib.h>
> +
> +#include "libqtest.h"
> +#include "qemu-common.h"
> +
> +#define IPMI_IRQ 5
> +
> +#define IPMI_BT_BASE 0xe4
> +
> +#define IPMI_BT_CTLREG_CLR_WR_PTR 0
> +#define IPMI_BT_CTLREG_CLR_RD_PTR 1
> +#define IPMI_BT_CTLREG_H2B_ATN 2
> +#define IPMI_BT_CTLREG_B2H_ATN 3
> +#define IPMI_BT_CTLREG_SMS_ATN 4
> +#define IPMI_BT_CTLREG_H_BUSY 6
> +#define IPMI_BT_CTLREG_B_BUSY 7
> +
> +#define IPMI_BT_CTLREG_GET(b) ((bt_get_ctrlreg() >> (b)) & 1)
> +#define IPMI_BT_CTLREG_GET_H2B_ATN()
> IPMI_BT_CTLREG_GET(IPMI_BT_CTLREG_H2B_ATN)
> +#define IPMI_BT_CTLREG_GET_B2H_ATN()
> IPMI_BT_CTLREG_GET(IPMI_BT_CTLREG_B2H_ATN)
> +#define IPMI_BT_CTLREG_GET_SMS_ATN()
> IPMI_BT_CTLREG_GET(IPMI_BT_CTLREG_SMS_ATN)
> +#define IPMI_BT_CTLREG_GET_H_BUSY()
> IPMI_BT_CTLREG_GET(IPMI_BT_CTLREG_H_BUSY)
> +#define IPMI_BT_CTLREG_GET_B_BUSY()
> IPMI_BT_CTLREG_GET(IPMI_BT_CTLREG_B_BUSY)
> +
> +#define IPMI_BT_CTLREG_SET(b) bt_write_ctrlreg(1 << (b))
> +#define IPMI_BT_CTLREG_SET_CLR_WR_PTR() IPMI_BT_CTLREG_SET( \
> +
> IPMI_BT_CTLREG_CLR_WR_PTR)
> +#define IPMI_BT_CTLREG_SET_CLR_RD_PTR() IPMI_BT_CTLREG_SET( \
> +
> IPMI_BT_CTLREG_CLR_RD_PTR)
> +#define IPMI_BT_CTLREG_SET_H2B_ATN()
> IPMI_BT_CTLREG_SET(IPMI_BT_CTLREG_H2B_ATN)
> +#define IPMI_BT_CTLREG_SET_B2H_ATN()
> IPMI_BT_CTLREG_SET(IPMI_BT_CTLREG_B2H_ATN)
> +#define IPMI_BT_CTLREG_SET_SMS_ATN()
> IPMI_BT_CTLREG_SET(IPMI_BT_CTLREG_SMS_ATN)
> +#define IPMI_BT_CTLREG_SET_H_BUSY()
> IPMI_BT_CTLREG_SET(IPMI_BT_CTLREG_H_BUSY)
> +
> +static int bt_ints_enabled;
> +
> +static uint8_t bt_get_ctrlreg(void)
> +{
> + return inb(IPMI_BT_BASE);
> +}
> +
> +static void bt_write_ctrlreg(uint8_t val)
> +{
> + outb(IPMI_BT_BASE, val);
> +}
> +
> +static uint8_t bt_get_buf(void)
> +{
> + return inb(IPMI_BT_BASE + 1);
> +}
> +
> +static void bt_write_buf(uint8_t val)
> +{
> + outb(IPMI_BT_BASE + 1, val);
> +}
> +
> +static uint8_t bt_get_irqreg(void)
> +{
> + return inb(IPMI_BT_BASE + 2);
> +}
> +
> +static void bt_write_irqreg(uint8_t val)
> +{
> + outb(IPMI_BT_BASE + 2, val);
> +}
> +
> +static void bt_wait_b_busy(void)
> +{
> + unsigned int count = 1000;
> + while (IPMI_BT_CTLREG_GET_B_BUSY() != 0) {
> + g_assert(--count != 0);
> + }
> +}
> +
> +static void bt_wait_b2h_atn(void)
> +{
> + unsigned int count = 1000;
> + while (IPMI_BT_CTLREG_GET_B2H_ATN() == 0) {
> + g_assert(--count != 0);
> + }
> +}
> +
> +
> +static int emu_lfd;
> +static int emu_fd;
> +static in_port_t emu_port;
> +static uint8_t inbuf[100];
> +static unsigned int inbuf_len;
> +static unsigned int inbuf_pos;
> +static int last_was_aa;
> +
> +static void read_emu_data(void)
> +{
> + fd_set readfds;
> + int rv;
> + struct timeval tv;
> +
> + FD_ZERO(&readfds);
> + FD_SET(emu_fd, &readfds);
> + tv.tv_sec = 10;
> + tv.tv_usec = 0;
> + rv = select(emu_fd + 1, &readfds, NULL, NULL, &tv);
> + if (rv == -1) {
> + perror("select");
> + }
> + g_assert(rv == 1);
> + rv = read(emu_fd, inbuf, sizeof(inbuf));
> + if (rv == -1) {
> + perror("read");
> + }
> + g_assert(rv > 0);
> + inbuf_len = rv;
> + inbuf_pos = 0;
> +}
> +
> +static void write_emu_msg(uint8_t *msg, unsigned int len)
> +{
> + int rv;
> +
> +#ifdef DEBUG_TEST
> + {
> + unsigned int i;
> + printf("sending:");
> + for (i = 0; i < len; i++) {
> + printf(" %2.2x", msg[i]);
> + }
> + printf("\n");
> + }
> +#endif
> + rv = write(emu_fd, msg, len);
> + g_assert(rv == len);
> +}
> +
> +static void get_emu_msg(uint8_t *msg, unsigned int *len)
> +{
> + unsigned int outpos = 0;
> +
> + for (;;) {
> + while (inbuf_pos < inbuf_len) {
> + uint8_t ch = inbuf[inbuf_pos++];
> +
> + g_assert(outpos < *len);
> + if (last_was_aa) {
> + assert(ch & 0x10);
> + msg[outpos++] = ch & ~0x10;
> + last_was_aa = 0;
> + } else if (ch == 0xaa) {
> + last_was_aa = 1;
> + } else {
> + msg[outpos++] = ch;
> + if ((ch == 0xa0) || (ch == 0xa1)) {
> + /* Message complete */
> + *len = outpos;
> + goto done;
> + }
> + }
> + }
> + read_emu_data();
> + }
> + done:
> +#ifdef DEBUG_TEST
> + {
> + unsigned int i;
> + printf("Msg:");
> + for (i = 0; i < outpos; i++) {
> + printf(" %2.2x", msg[i]);
> + }
> + printf("\n");
> + }
> +#endif
> + return;
> +}
> +
> +static uint8_t
> +ipmb_checksum(const unsigned char *data, int size, unsigned char
> start)
> +{
> + unsigned char csum = start;
> +
> + for (; size > 0; size--, data++) {
> + csum += *data;
> + }
> + return csum;
> +}
> +
> +static uint8_t get_dev_id_cmd[] = { 0x18, 0x01 };
> +static uint8_t get_dev_id_rsp[] = { 0x1c, 0x01, 0x00, 0x20, 0x00,
> 0x00, 0x00,
> + 0x02, 0x09, 0x00, 0x00, 0x00,
> 0x00, 0x00 };
> +
> +static uint8_t set_bmc_globals_cmd[] = { 0x18, 0x2e, 0x0f };
> +static uint8_t set_bmc_globals_rsp[] = { 0x1c, 0x2e, 0x00 };
> +static uint8_t enable_irq_cmd[] = { 0x05, 0xa1 };
> +
> +static void emu_msg_handler(void)
> +{
> + uint8_t msg[100];
> + unsigned int msg_len = sizeof(msg);
> +
> + get_emu_msg(msg, &msg_len);
> + g_assert(msg_len >= 5);
> + g_assert(msg[msg_len - 1] == 0xa0);
> + msg_len--;
> + g_assert(ipmb_checksum(msg, msg_len, 0) == 0);
> + msg_len--;
> + if ((msg[1] == get_dev_id_cmd[0]) && (msg[2] ==
> get_dev_id_cmd[1])) {
> + memcpy(msg + 1, get_dev_id_rsp, sizeof(get_dev_id_rsp));
> + msg_len = sizeof(get_dev_id_rsp) + 1;
> + msg[msg_len] = -ipmb_checksum(msg, msg_len, 0);
> + msg_len++;
> + msg[msg_len++] = 0xa0;
> + write_emu_msg(msg, msg_len);
> + } else if ((msg[1] == set_bmc_globals_cmd[0]) &&
> + (msg[2] == set_bmc_globals_cmd[1])) {
> + memcpy(msg + 1, set_bmc_globals_rsp,
> sizeof(set_bmc_globals_rsp));
> + msg_len = sizeof(set_bmc_globals_rsp) + 1;
> + msg[msg_len] = -ipmb_checksum(msg, msg_len, 0);
> + msg_len++;
> + msg[msg_len++] = 0xa0;
> + write_emu_msg(msg, msg_len);
> + write_emu_msg(enable_irq_cmd, sizeof(enable_irq_cmd));
> + } else {
> + g_assert(0);
> + }
> +}
> +
> +static void bt_cmd(uint8_t *cmd, unsigned int cmd_len,
> + uint8_t *rsp, unsigned int *rsp_len)
> +{
> + unsigned int i, len, j = 0;
> + uint8_t seq = 5;
> +
> + /* Should be idle */
> + g_assert(bt_get_ctrlreg() == 0);
> +
> + bt_wait_b_busy();
> + IPMI_BT_CTLREG_SET_CLR_WR_PTR();
> + bt_write_buf(cmd_len + 1);
> + bt_write_buf(cmd[0]);
> + bt_write_buf(seq);
> + for (i = 1; i < cmd_len; i++) {
> + bt_write_buf(cmd[i]);
> + }
> + IPMI_BT_CTLREG_SET_H2B_ATN();
> +
> + emu_msg_handler(); /* We should get a message on the socket
> here. */
> +
> + bt_wait_b2h_atn();
> + if (bt_ints_enabled) {
> + g_assert((bt_get_irqreg() & 0x02) == 0x02);
> + g_assert(get_irq(IPMI_IRQ));
> + bt_write_irqreg(0x03);
> + } else {
> + g_assert(!get_irq(IPMI_IRQ));
> + }
> + IPMI_BT_CTLREG_SET_H_BUSY();
> + IPMI_BT_CTLREG_SET_B2H_ATN();
> + IPMI_BT_CTLREG_SET_CLR_RD_PTR();
> + len = bt_get_buf();
> + g_assert(len >= 4);
> + rsp[0] = bt_get_buf();
> + assert(bt_get_buf() == seq);
> + len--;
> + for (j = 1; j < len; j++) {
> + rsp[j] = bt_get_buf();
> + }
> + IPMI_BT_CTLREG_SET_H_BUSY();
> + *rsp_len = j;
> +}
> +
> +
> +/*
> + * We should get a connect request and a short message with
> capabilities.
> + */
> +static void test_connect(void)
> +{
> + fd_set readfds;
> + int rv;
> + int val;
> + struct timeval tv;
> + uint8_t msg[100];
> + unsigned int msglen;
> + static uint8_t exp1[] = { 0xff, 0x01, 0xa1 }; /* A protocol
> version */
> + static uint8_t exp2[] = { 0x08, 0x1f, 0xa1 }; /* A
> capabilities cmd */
> + static uint8_t exp3[] = { 0x04, 0xa1 }; /* A reset is reported */
> +
> + FD_ZERO(&readfds);
> + FD_SET(emu_lfd, &readfds);
> + tv.tv_sec = 10;
> + tv.tv_usec = 0;
> + rv = select(emu_lfd + 1, &readfds, NULL, NULL, &tv);
> + g_assert(rv == 1);
> + emu_fd = accept(emu_lfd, NULL, 0);
> + if (emu_fd < 0) {
> + perror("accept");
> + }
> + g_assert(emu_fd >= 0);
> +
> + val = 1;
> + rv = setsockopt(emu_fd, IPPROTO_TCP, TCP_NODELAY, &val,
> sizeof(val));
> + g_assert(rv != -1);
> +
> + /* Report our version */
> + write_emu_msg(exp1, sizeof(exp1));
> +
> + /* Validate that we get the info we expect. */
> + msglen = sizeof(msg);
> + get_emu_msg(msg, &msglen);
> + g_assert(msglen == sizeof(exp1));
> + g_assert(memcmp(msg, exp1, msglen) == 0);
> + msglen = sizeof(msg);
> + get_emu_msg(msg, &msglen);
> + g_assert(msglen == sizeof(exp2));
> + g_assert(memcmp(msg, exp2, msglen) == 0);
> + msglen = sizeof(msg);
> + get_emu_msg(msg, &msglen);
> + g_assert(msglen == sizeof(exp3));
> + g_assert(memcmp(msg, exp3, msglen) == 0);
> +}
> +
> +/*
> + * Send a get_device_id to do a basic test.
> + */
> +static void test_bt_base(void)
> +{
> + uint8_t rsp[20];
> + unsigned int rsplen = sizeof(rsp);
> +
> + bt_cmd(get_dev_id_cmd, sizeof(get_dev_id_cmd), rsp, &rsplen);
> + g_assert(rsplen == sizeof(get_dev_id_rsp));
> + g_assert(memcmp(get_dev_id_rsp, rsp, rsplen) == 0);
> +}
> +
> +/*
> + * Enable IRQs for the interface.
> + */
> +static void test_enable_irq(void)
> +{
> + uint8_t rsp[20];
> + unsigned int rsplen = sizeof(rsp);
> +
> + bt_cmd(set_bmc_globals_cmd, sizeof(set_bmc_globals_cmd), rsp,
> &rsplen);
> + g_assert(rsplen == sizeof(set_bmc_globals_rsp));
> + g_assert(memcmp(set_bmc_globals_rsp, rsp, rsplen) == 0);
> + bt_write_irqreg(0x01);
> + bt_ints_enabled = 1;
> +}
> +
> +/*
> + * Create a local TCP socket with any port, then save off the
> port we got.
> + */
> +static void open_socket(void)
> +{
> + struct sockaddr_in myaddr;
> + socklen_t addrlen;
> +
> + myaddr.sin_family = AF_INET;
> + myaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
> + myaddr.sin_port = 0;
> + emu_lfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
> + if (emu_lfd == -1) {
> + perror("socket");
> + exit(1);
> + }
> + if (bind(emu_lfd, (struct sockaddr *) &myaddr,
> sizeof(myaddr)) == -1) {
> + perror("bind");
> + exit(1);
> + }
> + addrlen = sizeof(myaddr);
> + if (getsockname(emu_lfd, (struct sockaddr *) &myaddr ,
> &addrlen) == -1) {
> + perror("getsockname");
> + exit(1);
> + }
> + emu_port = ntohs(myaddr.sin_port);
> + assert(listen(emu_lfd, 1) != -1);
> +}
> +
> +int main(int argc, char **argv)
> +{
> + const char *arch = qtest_get_arch();
> + char *cmdline;
> + int ret;
> +
> + /* Check architecture */
> + if (strcmp(arch, "i386") && strcmp(arch, "x86_64")) {
> + g_test_message("Skipping test for non-x86\n");
> + return 0;
> + }
> +
> + open_socket();
> +
> + /* Run the tests */
> + g_test_init(&argc, &argv, NULL);
> +
> + cmdline = g_strdup_printf("-vnc none"
> + " -chardev
> socket,id=ipmi0,host=localhost,port=%d,reconnect=10"
> + " -device isa-ipmi,interface=bt,chardev=ipmi0", emu_port);
> + qtest_start(cmdline);
> + qtest_irq_intercept_in(global_qtest, "ioapic");
> + qtest_add_func("/ipmi/extern/connect", test_connect);
> + qtest_add_func("/ipmi/extern/bt_base", test_bt_base);
> + qtest_add_func("/ipmi/extern/bt_enable_irq", test_enable_irq);
> + qtest_add_func("/ipmi/extern/bt_base_irq", test_bt_base);
> + ret = g_test_run();
> + qtest_quit(global_qtest);
> +
> + return ret;
> +}
> diff --git a/tests/ipmi-kcs-test.c b/tests/ipmi-kcs-test.c
> new file mode 100644
> index 0000000..e2e1bdb
> --- /dev/null
> +++ b/tests/ipmi-kcs-test.c
> @@ -0,0 +1,294 @@
> +/*
> + * IPMI KCS test cases, using the local interface.
> + *
> + * Copyright (c) 2012 Corey Minyard <cminyard@mvista.com
> <mailto:cminyard@mvista.com>>
> + *
> + * 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 <stdint.h>
> +#include <string.h>
> +#include <stdio.h>
> +
> +#include <glib.h>
> +
> +#include "libqtest.h"
> +
> +#define IPMI_IRQ 5
> +
> +#define IPMI_KCS_BASE 0xca2
> +
> +#define IPMI_KCS_STATUS_ABORT 0x60
> +#define IPMI_KCS_CMD_WRITE_START 0x61
> +#define IPMI_KCS_CMD_WRITE_END 0x62
> +#define IPMI_KCS_CMD_READ 0x68
> +
> +#define IPMI_KCS_ABORTED_BY_CMD 0x01
> +
> +#define IPMI_KCS_CMDREG_GET_STATE() ((kcs_get_cmdreg() >> 6) & 3)
> +#define IPMI_KCS_STATE_IDLE 0
> +#define IPMI_KCS_STATE_READ 1
> +#define IPMI_KCS_STATE_WRITE 2
> +#define IPMI_KCS_STATE_ERROR 3
> +#define IPMI_KCS_CMDREG_GET_CD() ((kcs_get_cmdreg() >> 3) & 1)
> +#define IPMI_KCS_CMDREG_GET_ATN() ((kcs_get_cmdreg() >> 2) & 1)
> +#define IPMI_KCS_CMDREG_GET_IBF() ((kcs_get_cmdreg() >> 1) & 1)
> +#define IPMI_KCS_CMDREG_GET_OBF() ((kcs_get_cmdreg() >> 0) & 1)
> +
> +static int kcs_ints_enabled;
> +
> +static uint8_t kcs_get_cmdreg(void)
> +{
> + return inb(IPMI_KCS_BASE + 1);
> +}
> +
> +static void kcs_write_cmdreg(uint8_t val)
> +{
> + outb(IPMI_KCS_BASE + 1, val);
> +}
> +
> +static uint8_t kcs_get_datareg(void)
> +{
> + return inb(IPMI_KCS_BASE);
> +}
> +
> +static void kcs_write_datareg(uint8_t val)
> +{
> + outb(IPMI_KCS_BASE, val);
> +}
> +
> +static void kcs_wait_ibf(void)
> +{
> + unsigned int count = 1000;
> + while (IPMI_KCS_CMDREG_GET_IBF() != 0) {
> + g_assert(--count != 0);
> + }
> +}
> +
> +static void kcs_wait_obf(void)
> +{
> + unsigned int count = 1000;
> + while (IPMI_KCS_CMDREG_GET_OBF() == 0) {
> + g_assert(--count != 0);
> + }
> +}
> +
> +static void kcs_clear_obf(void)
> +{
> + if (kcs_ints_enabled) {
> + g_assert(get_irq(IPMI_IRQ));
> + } else {
> + g_assert(!get_irq(IPMI_IRQ));
> + }
> + g_assert(IPMI_KCS_CMDREG_GET_OBF() == 1);
> + kcs_get_datareg();
> + g_assert(IPMI_KCS_CMDREG_GET_OBF() == 0);
> + g_assert(!get_irq(IPMI_IRQ));
> +}
> +
> +static void kcs_check_state(uint8_t state)
> +{
> + g_assert(IPMI_KCS_CMDREG_GET_STATE() == state);
> +}
> +
> +static void kcs_cmd(uint8_t *cmd, unsigned int cmd_len,
> + uint8_t *rsp, unsigned int *rsp_len)
> +{
> + unsigned int i, j = 0;
> +
> + /* Should be idle */
> + g_assert(kcs_get_cmdreg() == 0);
> +
> + kcs_write_cmdreg(IPMI_KCS_CMD_WRITE_START);
> + kcs_wait_ibf();
> + kcs_check_state(IPMI_KCS_STATE_WRITE);
> + kcs_clear_obf();
> + for (i = 0; i < cmd_len; i++) {
> + kcs_write_datareg(cmd[i]);
> + kcs_wait_ibf();
> + kcs_check_state(IPMI_KCS_STATE_WRITE);
> + kcs_clear_obf();
> + }
> + kcs_write_cmdreg(IPMI_KCS_CMD_WRITE_END);
> + kcs_wait_ibf();
> + kcs_check_state(IPMI_KCS_STATE_WRITE);
> + kcs_clear_obf();
> + kcs_write_datareg(0);
> + next_read_byte:
> + kcs_wait_ibf();
> + switch (IPMI_KCS_CMDREG_GET_STATE()) {
> + case IPMI_KCS_STATE_READ:
> + kcs_wait_obf();
> + g_assert(j < *rsp_len);
> + rsp[j++] = kcs_get_datareg();
> + kcs_write_datareg(IPMI_KCS_CMD_READ);
> + goto next_read_byte;
> + break;
> +
> + case IPMI_KCS_STATE_IDLE:
> + kcs_wait_obf();
> + kcs_get_datareg();
> + break;
> +
> + default:
> + g_assert(0);
> + }
> + *rsp_len = j;
> +}
> +
> +static void kcs_abort(uint8_t *cmd, unsigned int cmd_len,
> + uint8_t *rsp, unsigned int *rsp_len)
> +{
> + unsigned int i, j = 0;
> + unsigned int retries = 4;
> +
> + /* Should be idle */
> + g_assert(kcs_get_cmdreg() == 0);
> +
> + kcs_write_cmdreg(IPMI_KCS_CMD_WRITE_START);
> + kcs_wait_ibf();
> + kcs_check_state(IPMI_KCS_STATE_WRITE);
> + kcs_clear_obf();
> + for (i = 0; i < cmd_len; i++) {
> + kcs_write_datareg(cmd[i]);
> + kcs_wait_ibf();
> + kcs_check_state(IPMI_KCS_STATE_WRITE);
> + kcs_clear_obf();
> + }
> + kcs_write_cmdreg(IPMI_KCS_CMD_WRITE_END);
> + kcs_wait_ibf();
> + kcs_check_state(IPMI_KCS_STATE_WRITE);
> + kcs_clear_obf();
> + kcs_write_datareg(0);
> + kcs_wait_ibf();
> + switch (IPMI_KCS_CMDREG_GET_STATE()) {
> + case IPMI_KCS_STATE_READ:
> + kcs_wait_obf();
> + g_assert(j < *rsp_len);
> + rsp[j++] = kcs_get_datareg();
> + kcs_write_datareg(IPMI_KCS_CMD_READ);
> + break;
> +
> + default:
> + g_assert(0);
> + }
> +
> + /* Start the abort here */
> + retry_abort:
> + g_assert(retries > 0);
> +
> + kcs_wait_ibf();
> + kcs_write_cmdreg(IPMI_KCS_STATUS_ABORT);
> + kcs_wait_ibf();
> + kcs_clear_obf();
> + kcs_write_datareg(0);
> + kcs_wait_ibf();
> + if (IPMI_KCS_CMDREG_GET_STATE() != IPMI_KCS_STATE_READ) {
> + retries--;
> + goto retry_abort;
> + }
> + kcs_wait_obf();
> + rsp[0] = kcs_get_datareg();
> + kcs_write_datareg(IPMI_KCS_CMD_READ);
> + kcs_wait_ibf();
> + if (IPMI_KCS_CMDREG_GET_STATE() != IPMI_KCS_STATE_IDLE) {
> + retries--;
> + goto retry_abort;
> + }
> + kcs_wait_obf();
> + kcs_clear_obf();
> +
> + *rsp_len = j;
> +}
> +
> +
> +static uint8_t get_dev_id_cmd[] = { 0x18, 0x01 };
> +static uint8_t get_dev_id_rsp[] = { 0x1c, 0x01, 0x00, 0x20, 0x00,
> 0x00, 0x00,
> + 0x02, 0x07, 0x00, 0x00, 0x00,
> 0x00, 0x00 };
> +
> +/*
> + * Send a get_device_id to do a basic test.
> + */
> +static void test_kcs_base(void)
> +{
> + uint8_t rsp[20];
> + unsigned int rsplen = sizeof(rsp);
> +
> + kcs_cmd(get_dev_id_cmd, sizeof(get_dev_id_cmd), rsp, &rsplen);
> + g_assert(rsplen == sizeof(get_dev_id_rsp));
> + g_assert(memcmp(get_dev_id_rsp, rsp, rsplen) == 0);
> +}
> +
> +/*
> + * Abort a kcs operation while reading
> + */
> +static void test_kcs_abort(void)
> +{
> + uint8_t rsp[20];
> + unsigned int rsplen = sizeof(rsp);
> +
> + kcs_abort(get_dev_id_cmd, sizeof(get_dev_id_cmd), rsp, &rsplen);
> + g_assert(rsp[0] == IPMI_KCS_ABORTED_BY_CMD);
> +}
> +
> +static uint8_t set_bmc_globals_cmd[] = { 0x18, 0x2e, 0x0f };
> +static uint8_t set_bmc_globals_rsp[] = { 0x1c, 0x2e, 0x00 };
> +
> +/*
> + * Enable interrupts
> + */
> +static void test_enable_irq(void)
> +{
> + uint8_t rsp[20];
> + unsigned int rsplen = sizeof(rsp);
> +
> + kcs_cmd(set_bmc_globals_cmd, sizeof(set_bmc_globals_cmd),
> rsp, &rsplen);
> + g_assert(rsplen == sizeof(set_bmc_globals_rsp));
> + g_assert(memcmp(set_bmc_globals_rsp, rsp, rsplen) == 0);
> + kcs_ints_enabled = 1;
> +}
> +
> +int main(int argc, char **argv)
> +{
> + const char *arch = qtest_get_arch();
> + char *cmdline;
> + int ret;
> +
> + /* Check architecture */
> + if (strcmp(arch, "i386") && strcmp(arch, "x86_64")) {
> + g_test_message("Skipping test for non-x86\n");
> + return 0;
> + }
> +
> + /* Run the tests */
> + g_test_init(&argc, &argv, NULL);
> +
> + cmdline = g_strdup_printf("-vnc none -device isa-ipmi");
> + qtest_start(cmdline);
> + qtest_irq_intercept_in(global_qtest, "ioapic");
> + qtest_add_func("/ipmi/local/kcs_base", test_kcs_base);
> + qtest_add_func("/ipmi/local/kcs_abort", test_kcs_abort);
> + qtest_add_func("/ipmi/local/kcs_enable_irq", test_enable_irq);
> + qtest_add_func("/ipmi/local/kcs_base_irq", test_kcs_base);
> + qtest_add_func("/ipmi/local/kcs_abort_irq", test_kcs_abort);
> + ret = g_test_run();
> + qtest_quit(global_qtest);
> +
> + return ret;
> +}
> --
> 1.8.3.1
>
>
next prev parent reply other threads:[~2013-11-13 20:52 UTC|newest]
Thread overview: 42+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-11-12 16:32 [Qemu-devel] [PATCH 00/16] Add an IPMI device to QEMU Corey Minyard
2013-11-12 16:33 ` [Qemu-devel] [PATCH 01/16] qemu-char: Allocate CharDriverState in qemu_chr_new_from_opts Corey Minyard
2014-01-23 13:32 ` Andreas Färber
2014-01-23 13:58 ` Andreas Färber
2013-11-12 16:33 ` [Qemu-devel] [PATCH 02/16] qemu-char: Allow a chardev to reconnect if disconnected Corey Minyard
2013-11-12 16:43 ` Eric Blake
2013-11-12 17:08 ` Corey Minyard
2013-11-14 7:32 ` Michael S. Tsirkin
2013-11-14 13:29 ` Corey Minyard
2013-11-13 8:55 ` Gerd Hoffmann
2013-11-13 20:51 ` Corey Minyard
2013-11-14 13:56 ` Michael S. Tsirkin
2013-11-12 16:33 ` [Qemu-devel] [PATCH 03/16] qemu-char: remove free of chr from win_stdio_close Corey Minyard
2013-11-12 16:33 ` [Qemu-devel] [PATCH 04/16] qemu-char: Close fd at end of file Corey Minyard
2013-11-12 16:33 ` [Qemu-devel] [PATCH 05/16] Add a base IPMI interface Corey Minyard
2013-11-12 16:33 ` [Qemu-devel] [PATCH 06/16] ipmi: Add a PC ISA type structure Corey Minyard
2014-01-29 14:58 ` Andreas Färber
2013-11-12 16:33 ` [Qemu-devel] [PATCH 07/16] ipmi: Add a KCS low-level interface Corey Minyard
2013-11-12 16:33 ` [Qemu-devel] [PATCH 08/16] ipmi: Add a BT " Corey Minyard
2013-11-12 16:33 ` [Qemu-devel] [PATCH 09/16] ipmi: Add a local BMC simulation Corey Minyard
2013-11-12 16:33 ` [Qemu-devel] [PATCH 10/16] ipmi: Add an external connection simulation interface Corey Minyard
2013-11-12 16:33 ` [Qemu-devel] [PATCH 11/16] ipmi: Add tests Corey Minyard
2013-11-13 14:12 ` Bret Ketchum
2013-11-13 20:51 ` Corey Minyard [this message]
2013-11-12 16:33 ` [Qemu-devel] [PATCH 12/16] ipmi: Add documentation Corey Minyard
2013-11-13 16:08 ` Bret Ketchum
2013-11-12 16:33 ` [Qemu-devel] [PATCH 13/16] ipmi: Add migration capability to the IPMI device Corey Minyard
2013-11-12 16:33 ` [Qemu-devel] [PATCH 14/16] pc: Postpone adding ACPI and SMBIOS to fw_cfg Corey Minyard
2013-11-13 14:31 ` Bret Ketchum
2013-11-14 7:30 ` Michael S. Tsirkin
2013-11-14 13:28 ` Corey Minyard
2013-11-14 13:38 ` Michael S. Tsirkin
2013-11-14 13:40 ` Corey Minyard
2013-11-14 13:50 ` Michael S. Tsirkin
2013-11-26 10:03 ` Michael S. Tsirkin
2013-11-12 16:33 ` [Qemu-devel] [PATCH 15/16] smbios: Add a function to directly add an entry Corey Minyard
2013-11-13 14:37 ` Bret Ketchum
2013-11-13 16:22 ` Andreas Färber
2013-11-13 20:52 ` Corey Minyard
2013-11-12 16:33 ` [Qemu-devel] [PATCH 16/16] ipmi: Add SMBIOS table entry Corey Minyard
2013-11-14 7:46 ` Michael S. Tsirkin
2013-11-14 13:43 ` Corey Minyard
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=5283E66D.2020304@mvista.com \
--to=cminyard@mvista.com \
--cc=bcketchum@gmail.com \
--cc=minyard@acm.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.