From patchwork Mon Jul 7 18:18:04 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Snow X-Patchwork-Id: 367673 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 3CB121400B8 for ; Tue, 8 Jul 2014 04:24:36 +1000 (EST) Received: from localhost ([::1]:52228 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1X4Dac-0004f5-2B for incoming@patchwork.ozlabs.org; Mon, 07 Jul 2014 14:24:34 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38959) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1X4DV6-0003OL-U4 for qemu-devel@nongnu.org; Mon, 07 Jul 2014 14:19:01 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1X4DUx-0004Hi-1e for qemu-devel@nongnu.org; Mon, 07 Jul 2014 14:18:52 -0400 Received: from mx1.redhat.com ([209.132.183.28]:53065) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1X4DUw-0004HO-OO for qemu-devel@nongnu.org; Mon, 07 Jul 2014 14:18:42 -0400 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id s67IIfuo020220 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Mon, 7 Jul 2014 14:18:42 -0400 Received: from dhcp-17-12.bos.redhat.com ([10.18.17.124]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id s67IIMNH020937; Mon, 7 Jul 2014 14:18:40 -0400 From: John Snow To: qemu-devel@nongnu.org Date: Mon, 7 Jul 2014 14:18:04 -0400 Message-Id: <1404757089-4836-24-git-send-email-jsnow@redhat.com> In-Reply-To: <1404757089-4836-1-git-send-email-jsnow@redhat.com> References: <1404757089-4836-1-git-send-email-jsnow@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.26 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Cc: pbonzini@redhat.com, John Snow , stefanha@redhat.com, mst@redhat.com Subject: [Qemu-devel] [PATCH 23/28] ahci: Adding basic functionality qtest. 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 Currently, there is no qtest to test the functionality of the AHCI functionality present within the Q35 machine type. This patch adds a skeleton for an AHCI test suite, and adds a simple sanity-check test case where we identify that the AHCI device is present, then disengage the virtual machine. Signed-off-by: John Snow --- tests/Makefile | 2 + tests/ahci-test.c | 207 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 209 insertions(+) create mode 100644 tests/ahci-test.c diff --git a/tests/Makefile b/tests/Makefile index 7e53d0d..71caa26 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -132,6 +132,7 @@ check-qtest-i386-y = tests/endianness-test$(EXESUF) check-qtest-i386-y += tests/fdc-test$(EXESUF) gcov-files-i386-y = hw/block/fdc.c check-qtest-i386-y += tests/ide-test$(EXESUF) +check-qtest-i386-y += tests/ahci-test$(EXESUF) check-qtest-i386-y += tests/hd-geo-test$(EXESUF) gcov-files-i386-y += hw/block/hd-geometry.c check-qtest-i386-y += tests/boot-order-test$(EXESUF) @@ -299,6 +300,7 @@ tests/endianness-test$(EXESUF): tests/endianness-test.o tests/spapr-phb-test$(EXESUF): tests/spapr-phb-test.o $(libqos-obj-y) tests/fdc-test$(EXESUF): tests/fdc-test.o tests/ide-test$(EXESUF): tests/ide-test.o $(libqos-pc-obj-y) +tests/ahci-test$(EXESUF): tests/ahci-test.o $(libqos-pc-obj-y) tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o tests/boot-order-test$(EXESUF): tests/boot-order-test.o $(libqos-obj-y) tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o $(libqos-obj-y) diff --git a/tests/ahci-test.c b/tests/ahci-test.c new file mode 100644 index 0000000..b3ed85f --- /dev/null +++ b/tests/ahci-test.c @@ -0,0 +1,207 @@ +/* + * AHCI test cases + * + * Copyright (c) 2014 John Snow + * + * 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 +#include +#include + +#include + +#include "libqtest.h" +#include "libqos/pci-pc.h" +#include "libqos/malloc-pc.h" + +#include "qemu-common.h" +#include "qemu/host-utils.h" + +#include "hw/pci/pci_ids.h" +#include "hw/pci/pci_regs.h" + +/* Test-specific defines. */ +#define TEST_IMAGE_SIZE (64 * 1024 * 1024) + +/*** Supplementary PCI Config Space IDs & Masks ***/ +#define PCI_DEVICE_ID_INTEL_Q35_AHCI (0x2922) + +/* To help make it clear that the HBA is not a pointer to local memory. */ +typedef void HBA; + +/*** Globals ***/ +static QGuestAllocator *guest_malloc; +static QPCIBus *pcibus; +static char tmp_path[] = "/tmp/qtest.XXXXXX"; + +/*** Function Declarations ***/ +static QPCIDevice *get_ahci_device(void); +static void free_ahci_device(QPCIDevice *dev); + +/*** Utilities ***/ + +/** + * Locate, verify, and return a handle to the AHCI device. + */ +static QPCIDevice *get_ahci_device(void) +{ + QPCIDevice *ahci; + uint16_t vendor_id, device_id; + + pcibus = qpci_init_pc(); + + /* Find the AHCI PCI device and verify it's the right one. */ + ahci = qpci_device_find(pcibus, QPCI_DEVFN(0x1F, 0x02)); + g_assert(ahci != NULL); + + vendor_id = qpci_config_readw(ahci, PCI_VENDOR_ID); + device_id = qpci_config_readw(ahci, PCI_DEVICE_ID); + + g_assert(vendor_id == PCI_VENDOR_ID_INTEL); + g_assert(device_id == PCI_DEVICE_ID_INTEL_Q35_AHCI); + + return ahci; +} + +static void free_ahci_device(QPCIDevice *ahci) +{ + if (pcibus) { + qpci_free_pc(pcibus); + pcibus = NULL; + } + + /* libqos doesn't have a function for this, so free it manually */ + g_free(ahci); +} + +/*** Test Setup & Teardown ***/ + +/** + * Launch QEMU with the given command line, + * and then set up interrupts and our guest malloc interface. + */ +static void qtest_boot(const char *cmdline_fmt, ...) +{ + va_list ap; + char *cmdline; + + va_start(ap, cmdline_fmt); + cmdline = g_strdup_vprintf(cmdline_fmt, ap); + va_end(ap); + + qtest_start(cmdline); + qtest_irq_intercept_in(global_qtest, "ioapic"); + guest_malloc = pc_alloc_init(); + + free(cmdline); +} + +/** + * Tear down the QEMU instance. + */ +static void qtest_shutdown(void) +{ + if (guest_malloc) { + g_free(guest_malloc); + guest_malloc = NULL; + } + qtest_end(); +} + +/** + * Start a Q35 machine and bookmark a handle to the AHCI device. + */ +static void ahci_boot(QPCIDevice **ahci) +{ + QPCIDevice *dev; + + qtest_boot("-drive if=none,id=drive0,file=%s,cache=writeback,serial=%s" + " -M q35 " + "-device ide-hd,drive=drive0 " + "-global ide-hd.ver=%s", + tmp_path, "testdisk", "version"); + + /* Verify that we have an AHCI device present. */ + dev = get_ahci_device(); + + if (ahci) { + *ahci = dev; + } +} + +/** + * Clean up the PCI device, then terminate the QEMU instance. + */ +static void ahci_shutdown(QPCIDevice *ahci) +{ + free_ahci_device(ahci); + qtest_shutdown(); +} + +/******************************************************************************/ +/* Test Interfaces */ +/******************************************************************************/ + +/** + * Basic sanity test to boot a machine, find an AHCI device, and shutdown. + */ +static void test_sanity(void) +{ + QPCIDevice *ahci; + ahci_boot(&ahci); + ahci_shutdown(ahci); +} + +/******************************************************************************/ + +int main(int argc, char **argv) +{ + const char *arch; + int fd; + int ret; + + /* Should be first to utilize g_test functionality, So we can see errors. */ + g_test_init(&argc, &argv, NULL); + + /* Check architecture */ + arch = qtest_get_arch(); + if (strcmp(arch, "i386") && strcmp(arch, "x86_64")) { + g_test_message("Skipping test for non-x86"); + return 0; + } + + /* Create a temporary raw image */ + fd = mkstemp(tmp_path); + g_assert(fd >= 0); + ret = ftruncate(fd, TEST_IMAGE_SIZE); + g_assert(ret == 0); + close(fd); + + /* Run the tests */ + qtest_add_func("/ahci/sanity", test_sanity); + + ret = g_test_run(); + + /* Cleanup */ + unlink(tmp_path); + + return ret; +}