From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50103) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bViTa-0000NP-NE for qemu-devel@nongnu.org; Fri, 05 Aug 2016 13:00:07 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bViTV-00037F-N0 for qemu-devel@nongnu.org; Fri, 05 Aug 2016 13:00:01 -0400 Received: from roura.ac.upc.edu ([147.83.33.10]:52958 helo=roura.ac.upc.es) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bViTV-000375-79 for qemu-devel@nongnu.org; Fri, 05 Aug 2016 12:59:57 -0400 From: =?utf-8?b?TGx1w61z?= Vilanova Date: Fri, 5 Aug 2016 18:59:56 +0200 Message-Id: <147041639594.2523.11799306197282230661.stgit@fimbulvetr.bsc.es> In-Reply-To: <147041636348.2523.2954972609232949598.stgit@fimbulvetr.bsc.es> References: <147041636348.2523.2954972609232949598.stgit@fimbulvetr.bsc.es> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Subject: [Qemu-devel] [PATCH 6/6] hypertrace: Add guest-side Linux module List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Stefan Hajnoczi Provides guest Linux kernel module "qemu-hypertrace.ko" to abstract access to the hypertrace channel. Signed-off-by: Llu=C3=ADs Vilanova --- Makefile | 4 - configure | 4 + hypertrace/guest/linux-module/Kbuild.in | 5 + hypertrace/guest/linux-module/Makefile | 24 ++++ .../include/linux/qemu-hypertrace-internal.h | 46 +++++++ .../linux-module/include/linux/qemu-hypertrace.h | 71 +++++++++++ hypertrace/guest/linux-module/qemu-hypertrace.c | 133 ++++++++++++++= ++++++ 7 files changed, 286 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-hype= rtrace-internal.h create mode 100644 hypertrace/guest/linux-module/include/linux/qemu-hype= rtrace.h create mode 100644 hypertrace/guest/linux-module/qemu-hypertrace.c diff --git a/Makefile b/Makefile index bebd6e6..26fb418 100644 --- a/Makefile +++ b/Makefile @@ -460,8 +460,10 @@ endif endif =20 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/linu= x/qemu-hypertrace.h" "$(DESTDIR)$(includedir)/linux" + $(INSTALL_DATA) "$(SRC_PATH)/hypertrace/guest/linux-module/include/linu= x/qemu-hypertrace-internal.h" "$(DESTDIR)$(includedir)/linux" =20 =20 install: all $(if $(BUILD_DOCS),install-doc) \ diff --git a/configure b/configure index 076eb8b..b809f69 100755 --- a/configure +++ b/configure @@ -5782,6 +5782,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/hypertra= ce/guest/user/Makefile +if test "$target_softmmu" =3D "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 =20 upper() { echo "$@"| LC_ALL=3DC tr '[a-z]' '[A-Z]' diff --git a/hypertrace/guest/linux-module/Kbuild.in b/hypertrace/guest/l= inux-module/Kbuild.in new file mode 100644 index 0000000..87656d4 --- /dev/null +++ b/hypertrace/guest/linux-module/Kbuild.in @@ -0,0 +1,5 @@ +# -*- mode: makefile -*- + +src =3D $(MOD_SRC_PATH) +ccflags-y :=3D -I$(src)/include/ -DHYPERTRACE_NUM_ARGS=3D$(HYPERTRACE_NU= M_ARGS) +obj-m :=3D qemu-hypertrace.o diff --git a/hypertrace/guest/linux-module/Makefile b/hypertrace/guest/li= nux-module/Makefile new file mode 100644 index 0000000..d9247a0 --- /dev/null +++ b/hypertrace/guest/linux-module/Makefile @@ -0,0 +1,24 @@ +include ../../../../config-host.mak +include ../../../config-target.mak +include $(SRC_PATH)/rules.mak + +MOD_SRC_PATH =3D $(SRC_PATH)/hypertrace/guest/linux-module + +LINUX_BUILD_PATH =3D /lib/modules/$(shell uname -r)/build + +vpath % $(MOD_SRC_PATH) + + +all: Kbuild + $(MAKE) -C $(LINUX_BUILD_PATH) M=3D$(shell pwd) \ + MOD_SRC_PATH=3D$(MOD_SRC_PATH) \ + HYPERTRACE_NUM_ARGS=3D$(CONFIG_HYPERTRACE_ARGS) \ + modules + +clean: Kbuild + $(MAKE) -C $(LINUX_BUILD_PATH) M=3D$(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..465c003 --- /dev/null +++ b/hypertrace/guest/linux-module/include/linux/qemu-hypertrace-interna= l.h @@ -0,0 +1,46 @@ +/* -*- C -*- + * + * Guest-side management of hypertrace. + * + * Copyright (C) 2016 Llu=C3=ADs 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_num_args; +extern uint64_t _qemu_hypertrace_channel_max_offset; +extern uint64_t *_qemu_hypertrace_channel_data; +extern uint64_t *_qemu_hypertrace_channel_control; + +static inline uint64_t qemu_hypertrace_num_args(void) +{ + return _qemu_hypertrace_channel_num_args; +} + +static inline uint64_t qemu_hypertrace_max_offset(void) +{ + return _qemu_hypertrace_channel_max_offset; +} + +static inline uint64_t *qemu_hypertrace_data(uint64_t data_offset) +{ + size_t args_size =3D qemu_hypertrace_num_args() * sizeof(uint64_t); + return &_qemu_hypertrace_channel_data[data_offset * args_size]; +} + +static inline void qemu_hypertrace (uint64_t data_offset) +{ + uint64_t *ctrlp =3D _qemu_hypertrace_channel_control; + ctrlp[1] =3D data_offset; +} 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..bb6ad7f --- /dev/null +++ b/hypertrace/guest/linux-module/include/linux/qemu-hypertrace.h @@ -0,0 +1,71 @@ +/* -*- C -*- + * + * Guest-side management of hypertrace. + * + * Copyright (C) 2016 Llu=C3=ADs 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_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_size: + * + * Maximum data offset value accepted by other calls. + */ +static uint64_t qemu_hypertrace_max_offset(void); + +/** + * qemu_hypertrace_data: + * @data_offset: Offset in multiples of argument packs. + * + * Pointer to the start of the data channel. + */ +static uint64_t *qemu_hypertrace_data(uint64_t data_offset); + +/** + * qemu_hypertrace: + * @data_offset: Offset in multiples of argument packs. + * + * Invoke the control channel. + * + * Each of the users (e.g., CPU) of the hypertrace channel can use a dif= ferent + * data offset 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 if= f 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 i= s + * re-scheduled). + */ +static void qemu_hypertrace(uint64_t data_offset); + + +#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..43d35d7 --- /dev/null +++ b/hypertrace/guest/linux-module/qemu-hypertrace.c @@ -0,0 +1,133 @@ +/* + * Guest-side management of hypertrace. + * + * Copyright (C) 2016 Llu=C3=ADs 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 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=C3=ADs Vilanova"); +MODULE_VERSION(VERSION_STR); + + +////////////////////////////////////////////////////////////////////// +// Kernel interface + +uint64_t _qemu_hypertrace_channel_num_args =3D HYPERTRACE_NUM_ARGS; +uint64_t _qemu_hypertrace_channel_max_offset =3D 0; +uint64_t *_qemu_hypertrace_channel_control =3D NULL; +uint64_t *_qemu_hypertrace_channel_data =3D NULL; + +EXPORT_SYMBOL(_qemu_hypertrace_channel_num_args); +EXPORT_SYMBOL(_qemu_hypertrace_channel_max_offset); +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 =3D pci_resource_start(dev, bar); + size =3D pci_resource_len(dev, bar); + + if (start =3D=3D 0 || size =3D=3D 0) { + return -ENOENT; + } + + res =3D ioremap(start, size); + if (res =3D=3D 0) { + return -EINVAL; + } + + *vaddr =3D res; + return 0; +} + +////////////////////////////////////////////////////////////////////// +// Module (de)initialization + +int init_module(void) +{ + int res =3D 0; + struct pci_dev *dev =3D NULL; + size_t args_size; + size_t data_size; + + printk(KERN_NOTICE "Loading QEMU hypertrace module (version %s)\n", + VERSION_STR); + + dev =3D pci_get_device(PCI_VENDOR_ID_REDHAT_QUMRANET, PCI_DEVICE_ID_= HYPERTRACE, NULL); + if (dev =3D=3D NULL) { + res =3D -ENOENT; + printk(KERN_ERR "Unable to find hypertrace device\n"); + goto error; + } + + res =3D init_channel(&_qemu_hypertrace_channel_control, dev, 0); + if (res !=3D 0) { + printk(KERN_ERR "Unable to find hypertrace control channel\n"); + goto error; + } + + res =3D init_channel(&_qemu_hypertrace_channel_data, dev, 1); + if (res !=3D 0) { + printk(KERN_ERR "Unable to find hypertrace data channel\n"); + goto error_data; + } + + args_size =3D _qemu_hypertrace_channel_num_args * sizeof(uint64_t); + data_size =3D pci_resource_len(dev, 1); + _qemu_hypertrace_channel_max_offset =3D data_size / args_size; + + goto ok; + +error_data: + iounmap(_qemu_hypertrace_channel_control); + +error: + _qemu_hypertrace_channel_control =3D NULL; + _qemu_hypertrace_channel_data =3D NULL; + +ok: + return res; +} + +void cleanup_module(void) +{ + printk(KERN_NOTICE "Unloading QEMU hypertrace module\n"); + + iounmap(_qemu_hypertrace_channel_control); + iounmap(_qemu_hypertrace_channel_data); +}