From 0c4c2323c05df7a0219f6a48a3175166f5fbc05b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Thu, 17 Jul 2014 02:27:33 +0200 Subject: [PATCH] Add VM kernel related files as qubes-core-vm-kernel-support package This is preparation for pvgrub support, where all VM kernel files will be installed inside of VM instead of dom0. But also the same could be used to prepare VM kernel image from any dom0 kernel. --- Makefile | 6 +- Makefile.builder | 2 +- dracut/Makefile | 4 + dracut/module-setup.sh | 15 +++ dracut/mount_modules.sh | 13 ++ dracut/qubes_cow_setup.sh | 31 +++++ kernel-modules/Makefile | 9 ++ kernel-modules/u2mfn/Makefile | 28 +++++ kernel-modules/u2mfn/dkms.conf.in | 7 ++ kernel-modules/u2mfn/u2mfn.c | 172 ++++++++++++++++++++++++++ rpm_spec/qubes-kernel-vm-support.spec | 72 +++++++++++ 11 files changed, 357 insertions(+), 2 deletions(-) create mode 100644 dracut/Makefile create mode 100644 dracut/module-setup.sh create mode 100644 dracut/mount_modules.sh create mode 100644 dracut/qubes_cow_setup.sh create mode 100644 kernel-modules/Makefile create mode 100644 kernel-modules/u2mfn/Makefile create mode 100644 kernel-modules/u2mfn/dkms.conf.in create mode 100644 kernel-modules/u2mfn/u2mfn.c create mode 100644 rpm_spec/qubes-kernel-vm-support.spec diff --git a/Makefile b/Makefile index 5dd41c5..5b81e05 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ help: rpms: rpmbuild --define "_rpmdir rpm/" --define "_builddir ." -bb rpm_spec/qubes-utils.spec -all: +all: $(MAKE) -C qrexec-lib all $(MAKE) -C qmemman all $(MAKE) -C core all @@ -25,6 +25,10 @@ install: $(MAKE) -C qmemman install $(MAKE) -C core install +install-kernel-support: + $(MAKE) -C dracut install + $(MAKE) -C kernel-modules install + clean: $(MAKE) -C qrexec-lib clean $(MAKE) -C qmemman clean diff --git a/Makefile.builder b/Makefile.builder index 8408483..c19f19c 100644 --- a/Makefile.builder +++ b/Makefile.builder @@ -1,3 +1,3 @@ -RPM_SPEC_FILES := rpm_spec/qubes-utils.spec +RPM_SPEC_FILES := rpm_spec/qubes-utils.spec rpm_spec/qubes-kernel-vm-support.spec ARCH_BUILD_DIRS := archlinux DEBIAN_BUILD_DIRS := debian diff --git a/dracut/Makefile b/dracut/Makefile new file mode 100644 index 0000000..272669f --- /dev/null +++ b/dracut/Makefile @@ -0,0 +1,4 @@ +install: + install -d $(DESTDIR)/usr/lib/dracut/modules.d/90qubes-vm + install module-setup.sh mount_modules.sh qubes_cow_setup.sh \ + $(DESTDIR)/usr/lib/dracut/modules.d/90qubes-vm/ diff --git a/dracut/module-setup.sh b/dracut/module-setup.sh new file mode 100644 index 0000000..6ce44bf --- /dev/null +++ b/dracut/module-setup.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +check() { + if xenstore-read qubes-vm-type &>/dev/null; then + return 0 + else + return 255 + fi +} + +install() { + inst_hook pre-udev 90 $moddir/qubes_cow_setup.sh + inst_hook pre-pivot 50 $moddir/mount_modules.sh + +} diff --git a/dracut/mount_modules.sh b/dracut/mount_modules.sh new file mode 100644 index 0000000..dc1c582 --- /dev/null +++ b/dracut/mount_modules.sh @@ -0,0 +1,13 @@ +# +# This file should be places in pre-pivot directory in dracut's initramfs +# + +#!/bin/sh + +if ! [ -d $NEWROOT/lib/modules/`uname -r` ]; then + echo "Waiting for /dev/xvdd device..." + while ! [ -e /dev/xvdd ]; do sleep 0.1; done + + mount -n -t ext3 /dev/xvdd $NEWROOT/lib/modules +fi + diff --git a/dracut/qubes_cow_setup.sh b/dracut/qubes_cow_setup.sh new file mode 100644 index 0000000..19bb9d3 --- /dev/null +++ b/dracut/qubes_cow_setup.sh @@ -0,0 +1,31 @@ +# +# This file should be places in pre-mount directory in dracut's initramfs +# + +#!/bin/sh +echo "Qubes initramfs script here:" + +if [ -e /dev/mapper/dmroot ] ; then + die "Qubes: FATAL error: /dev/mapper/dmroot already exists?!" +fi + +modprobe xenblk || modprobe xen-blkfront || echo "Qubes: Cannot load Xen Block Frontend..." + +echo "Waiting for /dev/xvda* devices..." +while ! [ -e /dev/xvda ]; do sleep 0.1; done + +if [ `cat /sys/block/xvda/ro` = 1 ] ; then + echo "Qubes: Doing COW setup for AppVM..." + + while ! [ -e /dev/xvdc ]; do sleep 0.1; done + while ! [ -e /dev/xvdc2 ]; do sleep 0.1; done + + echo "0 `cat /sys/block/xvda/size` snapshot /dev/xvda /dev/xvdc2 N 16" | \ + dmsetup create dmroot || { echo "Qubes: FATAL: cannot create dmroot!"; } + echo Qubes: done. +else + echo "Qubes: Doing R/W setup for TemplateVM..." + echo "0 `cat /sys/block/xvda/size` linear /dev/xvda 0" | \ + dmsetup create dmroot || { echo "Qubes: FATAL: cannot create dmroot!"; exit 1; } + echo Qubes: done. +fi diff --git a/kernel-modules/Makefile b/kernel-modules/Makefile new file mode 100644 index 0000000..3f94fe7 --- /dev/null +++ b/kernel-modules/Makefile @@ -0,0 +1,9 @@ +ver := $(shell cat ../version) +srcdir := /usr/src/u2mfn-$(ver) + +install: install-u2mfn + +install-u2mfn: + install -d $(DESTDIR)$(srcdir) + install -m 644 u2mfn/u2mfn.c u2mfn/Makefile $(DESTDIR)$(srcdir) + sed -e 's#@@VERSION@@#$(ver)#' u2mfn/dkms.conf.in > $(DESTDIR)$(srcdir)/dkms.conf diff --git a/kernel-modules/u2mfn/Makefile b/kernel-modules/u2mfn/Makefile new file mode 100644 index 0000000..59e222d --- /dev/null +++ b/kernel-modules/u2mfn/Makefile @@ -0,0 +1,28 @@ +# +# The Qubes OS Project, http://www.qubes-os.org +# +# Copyright (C) 2010 Rafal Wojtczuk +# +# 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 2 +# 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, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# + +obj-m += u2mfn.o + +clean: + rm -f *.o *.ko *~ + rm -f .u2mfn.* *.mod.c Module.symvers modules.order + rm -fr .tmp_versions + rm -f Makefile.xen diff --git a/kernel-modules/u2mfn/dkms.conf.in b/kernel-modules/u2mfn/dkms.conf.in new file mode 100644 index 0000000..96ddd70 --- /dev/null +++ b/kernel-modules/u2mfn/dkms.conf.in @@ -0,0 +1,7 @@ +PACKAGE_VERSION="@@VERSION@@" + +# Items below here should not have to change with each driver version +PACKAGE_NAME="u2mfn" + +BUILT_MODULE_NAME[0]="u2mfn" +DEST_MODULE_LOCATION[0]="/extra/" diff --git a/kernel-modules/u2mfn/u2mfn.c b/kernel-modules/u2mfn/u2mfn.c new file mode 100644 index 0000000..bd88df4 --- /dev/null +++ b/kernel-modules/u2mfn/u2mfn.c @@ -0,0 +1,172 @@ +/* + * The Qubes OS Project, http://www.qubes-os.org + * + * Copyright (C) 2010 Rafal Wojtczuk + * + * 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#ifndef FOREIGN_FRAME_BIT +#include +#endif +#include + +/* copy of /usr/include/u2mfn-kernel.h, to reduce requirements */ +#include +#define U2MFN_MAGIC 0xf5 +#define U2MFN_GET_MFN_FOR_PAGE _IOW(U2MFN_MAGIC, 1, int) +#define U2MFN_GET_LAST_MFN _IO(U2MFN_MAGIC, 2) + + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0) +static inline unsigned long virt_to_phys(volatile void *address) +{ + return __pa((unsigned long) address); +} +#endif + +#ifdef virt_to_mfn +#define VIRT_TO_MFN virt_to_mfn +#else +extern unsigned long *phys_to_machine_mapping; +static inline unsigned long VIRT_TO_MFN(void *addr) +{ + unsigned int pfn = virt_to_phys(addr) >> PAGE_SHIFT; + return phys_to_machine_mapping[pfn] & ~FOREIGN_FRAME_BIT; +} +#endif + +/// User virtual address to mfn translator +/** + \param cmd ignored + \param data the user-specified address + \return mfn corresponding to "data" argument, or -1 on error +*/ +static long u2mfn_ioctl(struct file *f, unsigned int cmd, + unsigned long data) +{ + struct page *user_page; + void *kaddr; + int ret; + + if (_IOC_TYPE(cmd) != U2MFN_MAGIC) { + printk("Qubes u2mfn: wrong IOCTL magic"); + return -ENOTTY; + } + + switch (cmd) { + case U2MFN_GET_MFN_FOR_PAGE: + down_read(¤t->mm->mmap_sem); + ret = get_user_pages + (current, current->mm, data, 1, 1, 0, &user_page, 0); + up_read(¤t->mm->mmap_sem); + if (ret != 1) { + printk("U2MFN_GET_MFN_FOR_PAGE: get_user_pages failed, ret=0x%x\n", ret); + return -1; + } + kaddr = kmap(user_page); + ret = VIRT_TO_MFN(kaddr); + kunmap(user_page); + put_page(user_page); + break; + + case U2MFN_GET_LAST_MFN: + if (f->private_data) + ret = VIRT_TO_MFN(f->private_data); + else + ret = 0; + break; + + default: + printk("Qubes u2mfn: wrong ioctl passed!\n"); + return -ENOTTY; + } + + + return ret; +} + +static int u2mfn_mmap(struct file *f, struct vm_area_struct *vma) +{ + int ret; + char *kbuf; + long length = vma->vm_end - vma->vm_start; + printk("u2mfn_mmap: entering, private=%p\n", f->private_data); + if (f->private_data) + return -EBUSY; + if (length != PAGE_SIZE) + return -EINVAL; + kbuf = (char *) __get_free_page(GFP_KERNEL); + if (!kbuf) + return -ENOMEM; + + f->private_data = kbuf; + + ret = remap_pfn_range(vma, vma->vm_start, + virt_to_phys(kbuf) >> PAGE_SHIFT, + length, vma->vm_page_prot); + + printk("u2mfn_mmap: calling remap return %d\n", ret); + if (ret) + return ret; + + + return 0; +} + +static int u2mfn_release(struct inode *i, struct file *f) +{ + printk("u2mfn_release, priv=%p\n", f->private_data); + if (f->private_data) + __free_page(f->private_data); + f->private_data = NULL; + return 0; +} + +static struct file_operations u2mfn_fops = { + .unlocked_ioctl = u2mfn_ioctl, + .mmap = u2mfn_mmap, + .release = u2mfn_release +}; + +/// u2mfn module registration +/** + tries to register "/proc/u2mfn" pseudofile +*/ +static int u2mfn_init(void) +{ + struct proc_dir_entry *u2mfn_node = + proc_create_data("u2mfn", 0666, NULL, + &u2mfn_fops, 0); + if (!u2mfn_node) + return -1; + return 0; +} + +static void u2mfn_exit(void) +{ + remove_proc_entry("u2mfn", 0); +} + +module_init(u2mfn_init); +module_exit(u2mfn_exit); +MODULE_LICENSE("GPL"); diff --git a/rpm_spec/qubes-kernel-vm-support.spec b/rpm_spec/qubes-kernel-vm-support.spec new file mode 100644 index 0000000..30c0995 --- /dev/null +++ b/rpm_spec/qubes-kernel-vm-support.spec @@ -0,0 +1,72 @@ +# +# The Qubes OS Project, http://www.qubes-os.org +# +# Copyright (C) 2015 Marek Marczykowski-Górecki +# +# +# 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 2 +# 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, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# + + +%{!?version: %define version %(cat version)} + +Name: qubes-kernel-vm-support +Version: %{version} +Release: 1%{?dist} +Summary: Qubes VM kernel and initramfs modules + +Group: Qubes +Vendor: Invisible Things Lab +License: GPL v2 only +URL: http://www.qubes-os.org + +Requires: dracut +Requires: dkms + +%define _builddir %(pwd) + +%description +This package contains: +1. Dracut module required to setup Qubes VM root filesystem. This package is +needed in VM only when the VM uses its own kernel (via pvgrub or so). Otherwise +initrd is provided by dom0. + +2. u2mfn kernel module sources (dkms) required by GUI agent and R2 version of +libvchan library. + +%prep +# we operate on the current directory, so no need to unpack anything +# symlink is to generate useful debuginfo packages +rm -f %{name}-%{version} +ln -sf . %{name}-%{version} +%setup -T -D + +%build + +%install +make install-kernel-support DESTDIR=%{buildroot} + +%files +/usr/lib/dracut/modules.d/90qubes-vm +/usr/src/u2mfn-%{version}/ + +%post +dkms add -m u2mfn -v %{version} --rpm_safe_upgrade + +%preun +dkms remove -m u2mfn -v %{version} --all --rpm_safe_upgrade + +%changelog +