From patchwork Mon Sep 5 18:56:54 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Llu=C3=ADs_Vilanova?= X-Patchwork-Id: 9315087 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 3ED4E607D3 for ; Mon, 5 Sep 2016 19:21:14 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 30F9F284D8 for ; Mon, 5 Sep 2016 19:21:14 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 25A3528901; Mon, 5 Sep 2016 19:21:14 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 043BE284D8 for ; Mon, 5 Sep 2016 19:21:12 +0000 (UTC) Received: from localhost ([::1]:56584 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bgzSB-0008GA-Pk for patchwork-qemu-devel@patchwork.kernel.org; Mon, 05 Sep 2016 15:21:11 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44857) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bgz4l-0005YZ-BJ for qemu-devel@nongnu.org; Mon, 05 Sep 2016 14:57:05 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bgz4i-0008Rv-CD for qemu-devel@nongnu.org; Mon, 05 Sep 2016 14:56:58 -0400 Received: from roura.ac.upc.edu ([147.83.33.10]:57356 helo=roura.ac.upc.es) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bgz4h-0008Rl-Sx for qemu-devel@nongnu.org; Mon, 05 Sep 2016 14:56:56 -0400 Received: from gw-2.ac.upc.es (gw-2.ac.upc.es [147.83.30.8]) by roura.ac.upc.es (8.13.8/8.13.8) with ESMTP id u85Iut6U001969; Mon, 5 Sep 2016 20:56:55 +0200 Received: from localhost (unknown [84.88.51.85]) by gw-2.ac.upc.es (Postfix) with ESMTPSA id E595A3B1; Mon, 5 Sep 2016 20:56:54 +0200 (CEST) From: =?utf-8?b?TGx1w61z?= Vilanova To: qemu-devel@nongnu.org Date: Mon, 5 Sep 2016 20:56:54 +0200 Message-Id: <147310181464.10840.16302124741271761852.stgit@fimbulvetr.bsc.es> X-Mailer: git-send-email 2.9.3 In-Reply-To: <147310178240.10840.14758930096407696981.stgit@fimbulvetr.bsc.es> References: <147310178240.10840.14758930096407696981.stgit@fimbulvetr.bsc.es> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 X-MIME-Autoconverted: from 8bit to quoted-printable by roura.ac.upc.es id u85Iut6U001969 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6.x X-Received-From: 147.83.33.10 Subject: [Qemu-devel] [PATCH v2 6/6] hypertrace: Add guest-side Linux module X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Stefan Hajnoczi , Luiz Capitulino Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP Provides guest Linux kernel module "qemu-hypertrace.ko" to abstract access to the hypertrace channel. Signed-off-by: Lluís Vilanova --- Makefile | 4 - configure | 4 + hypertrace/guest/linux-module/Kbuild.in | 7 + hypertrace/guest/linux-module/Makefile | 23 +++ .../include/linux/qemu-hypertrace-internal.h | 46 ++++++ .../linux-module/include/linux/qemu-hypertrace.h | 73 ++++++++++ hypertrace/guest/linux-module/qemu-hypertrace.c | 146 ++++++++++++++++++++ 7 files changed, 302 insertions(+), 1 deletion(-) create mode 100644 hypertrace/guest/linux-module/Kbuild.in create mode 100644 hypertrace/guest/linux-module/Makefile create mode 100644 hypertrace/guest/linux-module/include/linux/qemu-hypertrace-internal.h create mode 100644 hypertrace/guest/linux-module/include/linux/qemu-hypertrace.h create mode 100644 hypertrace/guest/linux-module/qemu-hypertrace.c diff --git a/Makefile b/Makefile index 8fb469b..4a47823 100644 --- a/Makefile +++ b/Makefile @@ -461,8 +461,10 @@ endif endif install-hypertrace: - $(INSTALL_DIR) "$(DESTDIR)$(includedir)" + $(INSTALL_DIR) "$(DESTDIR)$(includedir)/linux" $(INSTALL_DATA) "$(SRC_PATH)/hypertrace/guest/user/qemu-hypertrace.h" "$(DESTDIR)$(includedir)/" + $(INSTALL_DATA) "$(SRC_PATH)/hypertrace/guest/linux-module/include/linux/qemu-hypertrace.h" "$(DESTDIR)$(includedir)/linux" + $(INSTALL_DATA) "$(SRC_PATH)/hypertrace/guest/linux-module/include/linux/qemu-hypertrace-internal.h" "$(DESTDIR)$(includedir)/linux" install: all $(if $(BUILD_DOCS),install-doc) \ diff --git a/configure b/configure index ad83fff..fadaaf5 100755 --- a/configure +++ b/configure @@ -5795,6 +5795,10 @@ fi symlink "$source_path/Makefile.target" "$target_dir/Makefile" mkdir -p $target_dir/hypertrace/guest/user symlink $source_path/hypertrace/guest/user/Makefile $target_dir/hypertrace/guest/user/Makefile +if test "$target_softmmu" = "yes"; then + mkdir -p $target_dir/hypertrace/guest/linux-module + symlink $source_path/hypertrace/guest/linux-module/Makefile $target_dir/hypertrace/guest/linux-module/Makefile +fi upper() { echo "$@"| LC_ALL=C tr '[a-z]' '[A-Z]' diff --git a/hypertrace/guest/linux-module/Kbuild.in b/hypertrace/guest/linux-module/Kbuild.in new file mode 100644 index 0000000..56abaea --- /dev/null +++ b/hypertrace/guest/linux-module/Kbuild.in @@ -0,0 +1,7 @@ +# -*- mode: makefile -*- + +COMMON_H = $(shell readlink -f $(MOD_SRC_PATH)/../../common.h) + +src = $(MOD_SRC_PATH) +ccflags-y := -I$(src)/include/ -DCOMMON_H=$(COMMON_H) +obj-m := qemu-hypertrace.o diff --git a/hypertrace/guest/linux-module/Makefile b/hypertrace/guest/linux-module/Makefile new file mode 100644 index 0000000..b30cdeb --- /dev/null +++ b/hypertrace/guest/linux-module/Makefile @@ -0,0 +1,23 @@ +include ../../../../config-host.mak +include ../../../config-target.mak +include $(SRC_PATH)/rules.mak + +MOD_SRC_PATH = $(SRC_PATH)/hypertrace/guest/linux-module + +LINUX_BUILD_PATH = /lib/modules/$(shell uname -r)/build + +vpath % $(MOD_SRC_PATH) + + +all: Kbuild + $(MAKE) -C $(LINUX_BUILD_PATH) M=$(shell pwd) \ + MOD_SRC_PATH=$(MOD_SRC_PATH) \ + modules + +clean: Kbuild + $(MAKE) -C $(LINUX_BUILD_PATH) M=$(shell pwd) clean + rm -f $< + +Kbuild: $(MOD_SRC_PATH)/Kbuild.in Makefile + rm -f $@ + cp $< $@ diff --git a/hypertrace/guest/linux-module/include/linux/qemu-hypertrace-internal.h b/hypertrace/guest/linux-module/include/linux/qemu-hypertrace-internal.h new file mode 100644 index 0000000..63dfee0 --- /dev/null +++ b/hypertrace/guest/linux-module/include/linux/qemu-hypertrace-internal.h @@ -0,0 +1,46 @@ +/* -*- C -*- + * + * Guest-side management of hypertrace. + * + * Copyright (C) 2016 Lluís Vilanova + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ + +extern uint64_t _qemu_hypertrace_channel_max_clients; +extern uint64_t _qemu_hypertrace_channel_num_args; +extern uint64_t *_qemu_hypertrace_channel_data; +extern uint64_t *_qemu_hypertrace_channel_control; + +static inline uint64_t qemu_hypertrace_max_clients(void) +{ + return _qemu_hypertrace_channel_max_clients; +} + +static inline uint64_t qemu_hypertrace_num_args(void) +{ + return _qemu_hypertrace_channel_num_args; +} + +static inline uint64_t *qemu_hypertrace_data(uint64_t client) +{ + size_t args_size = qemu_hypertrace_num_args() * sizeof(uint64_t); + return &_qemu_hypertrace_channel_data[client * args_size]; +} + +static inline void qemu_hypertrace (uint64_t client, uint64_t arg1) +{ + uint64_t *ctrlp = _qemu_hypertrace_channel_control; + ctrlp[client] = arg1; +} diff --git a/hypertrace/guest/linux-module/include/linux/qemu-hypertrace.h b/hypertrace/guest/linux-module/include/linux/qemu-hypertrace.h new file mode 100644 index 0000000..f4b70c9 --- /dev/null +++ b/hypertrace/guest/linux-module/include/linux/qemu-hypertrace.h @@ -0,0 +1,73 @@ +/* -*- C -*- + * + * Guest-side management of hypertrace. + * + * Copyright (C) 2016 Lluís Vilanova + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ + +#ifndef QEMU_HYPERTRACE_H +#define QEMU_HYPERTRACE_H + +#include + + +/** + * qemu_hypertrace_max_clients: + * + * Maximum number of concurrent clients accepted by other calls. + */ +static uint64_t qemu_hypertrace_max_clients(void); + +/** + * qemu_hypertrace_num_args: + * + * Number of uint64_t values read by each call to qemu_hypertrace(). + */ +static uint64_t qemu_hypertrace_num_args(void); + +/** + * qemu_hypertrace_data: + * @client: Client identifier. + * + * Pointer to the start of the data channel for the given client. Clients must + * write their arguments there (all but the first one). + */ +static uint64_t *qemu_hypertrace_data(uint64_t client); + +/** + * qemu_hypertrace: + * @client: Client identifier. + * @arg1: First argument of the hypertrace event. + * + * Emit a hypertrace event. + * + * Each of the clients (e.g., CPU) must use a different client identifier to + * ensure they can work concurrently without using locks (i.e., each uses a + * different portion of the data channel). + * + * Note: You should use wmb() before writing into the control channel iff you + * have written into the data channel. + * + * Note: Use preempt_disable() and preempt_enable() if you're using data offsets + * based on the CPU identifiers (or else data might be mixed if a task is + * re-scheduled). + */ +static void qemu_hypertrace(uint64_t client, uint64_t arg1); + + +#include + +#endif /* QEMU_HYPERTRACE_H */ diff --git a/hypertrace/guest/linux-module/qemu-hypertrace.c b/hypertrace/guest/linux-module/qemu-hypertrace.c new file mode 100644 index 0000000..901d424 --- /dev/null +++ b/hypertrace/guest/linux-module/qemu-hypertrace.c @@ -0,0 +1,146 @@ +/* + * Guest-side management of hypertrace. + * + * Copyright (C) 2016 Lluís Vilanova + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ + +#include + +#include +#include +#include + +#define xstr(s) #s +#define str(s) xstr(s) +#include str(COMMON_H) + + +#define VERSION_STR "0.1" +#define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4 +#define PCI_DEVICE_ID_HYPERTRACE 0x10f0 + + +MODULE_DESCRIPTION("Kernel interface to QEMU's hypertrace device"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Lluís Vilanova"); +MODULE_VERSION(VERSION_STR); + + +////////////////////////////////////////////////////////////////////// +// Kernel interface + +uint64_t _qemu_hypertrace_channel_max_clients; +uint64_t _qemu_hypertrace_channel_num_args; +static uint64_t *_qemu_hypertrace_channel_config; +uint64_t *_qemu_hypertrace_channel_data; +uint64_t *_qemu_hypertrace_channel_control; + +EXPORT_SYMBOL(_qemu_hypertrace_channel_max_clients); +EXPORT_SYMBOL(_qemu_hypertrace_channel_num_args); +EXPORT_SYMBOL(_qemu_hypertrace_channel_data); +EXPORT_SYMBOL(_qemu_hypertrace_channel_control); + + +////////////////////////////////////////////////////////////////////// +// Channel initialization + +static +int +init_channel (uint64_t **vaddr, struct pci_dev *dev, int bar) +{ + void * res; + resource_size_t start, size; + + start = pci_resource_start(dev, bar); + size = pci_resource_len(dev, bar); + + if (start == 0 || size == 0) { + return -ENOENT; + } + + res = ioremap(start, size); + if (res == 0) { + return -EINVAL; + } + + *vaddr = res; + return 0; +} + +////////////////////////////////////////////////////////////////////// +// Module (de)initialization + +int init_module(void) +{ + int res = 0; + struct pci_dev *dev = NULL; + struct hypertrace_config *config; + + printk(KERN_NOTICE "Loading QEMU hypertrace module (version %s)\n", + VERSION_STR); + + dev = pci_get_device(PCI_VENDOR_ID_REDHAT_QUMRANET, PCI_DEVICE_ID_HYPERTRACE, NULL); + if (dev == NULL) { + res = -ENOENT; + printk(KERN_ERR "Unable to find hypertrace device\n"); + goto error; + } + + res = init_channel(&_qemu_hypertrace_channel_config, dev, 0); + if (res != 0) { + printk(KERN_ERR "Unable to find hypertrace config channel\n"); + goto error; + } + + config = (struct hypertrace_config*)_qemu_hypertrace_channel_config; + _qemu_hypertrace_channel_max_clients = config->max_clients; + _qemu_hypertrace_channel_num_args = config->client_args; + + res = init_channel(&_qemu_hypertrace_channel_data, dev, 1); + if (res != 0) { + printk(KERN_ERR "Unable to find hypertrace data channel\n"); + goto error_config; + } + + res = init_channel(&_qemu_hypertrace_channel_control, dev, 0); + if (res != 0) { + printk(KERN_ERR "Unable to find hypertrace control channel\n"); + goto error_data; + } + + goto ok; + +error_data: + iounmap(_qemu_hypertrace_channel_data); + +error_config: + iounmap(_qemu_hypertrace_channel_config); + _qemu_hypertrace_channel_config = NULL; + _qemu_hypertrace_channel_data = NULL; + +error: +ok: + return res; +} + +void cleanup_module(void) +{ + printk(KERN_NOTICE "Unloading QEMU hypertrace module\n"); + + iounmap(_qemu_hypertrace_channel_config); + iounmap(_qemu_hypertrace_channel_data); + iounmap(_qemu_hypertrace_channel_control); +}