diff --git a/conf/distro/openxt-tip.conf b/conf/distro/openxt-tip.conf new file mode 100644 index 0000000000..ccd96feb4f --- /dev/null +++ b/conf/distro/openxt-tip.conf @@ -0,0 +1,120 @@ +# +# This is how bitbake will establish its configuration: +# +# require conf/abi_version.conf +# include conf/site.conf +# include conf/auto.conf +# include conf/local.conf +# include conf/build/${BUILD_SYS}.conf +# include conf/target/${TARGET_SYS}.conf +# include conf/machine/${MACHINE}.conf +# include conf/machine-sdk/${SDKMACHINE}.conf +# include conf/distro/${DISTRO}.conf +# include conf/distro/defaultsetup.conf +# include conf/documentation.conf +# include conf/licenses.conf +# require conf/sanity.conf +# + +# openembedded-core sets a default list of DISTRO_FEATURES that do not match +# OpenXT's machine needs. +# See: openembedded-core/meta/conf/distro/include/default-distrovars.inc +# Another way would be hard setting DISTRO_FEATURES. +# Another way would be to redefine DISTRO_FEATURES_DEFAULT. +# Down the road this should probably be a machine config thing so it is possible +# to have images that do not include selinux +DISTRO_FEATURES_remove = "zeroconf nfs" +DISTRO_FEATURES_append += "pam selinux multiarch virtualization polkit opengl" + +# Dojosdk preferred version. +PREFERRED_VERSION_dojosdk-native ?= "1.7.12" +# ${MACHINE}.conf is overriden by ${DISTRO}.conf +# xenmgr_data and sync-wui (uivm and syncui machines) apparently depends on +# different versions, so preserve that. +PREFERRED_VERSION_dojosdk-native_xenclient-syncui ?= "1.8.1" + +# Prefer openssl to libressl. +PREFERRED_PROVIDER_openssl = "openssl" +PREFERRED_PROVIDER_openssl-native = "openssl-native" +PREFERRED_PROVIDER_openssl-conf = "openssl-conf" +PREFERRED_PROVIDER_nativesdk-openssl = "nativesdk-openssl" +PREFERRED_PROVIDER_nativesdk-openssl-conf = "nativesdk-openssl-conf" +# Prefer libcrypto and libssl to alternatives. +PREFERRED_PROVIDER_libcrypto = "libcrypto" +PREFERRED_PROVIDER_libssl = "libssl" + +# Prefer libx11 to libx11-diet. +PREFERRED_PROVIDER_virtual/libx11 = "libx11" + +# Force specific package versions +PREFERRED_VERSION_networkmanager = "1.18.4" +PREFERRED_VERSION_network-manager-applet = "1.8.22" + +PREFERRED_PROVIDER_iasl = "acpica" +PREFERRED_PROVIDER_iasl-native = "${PREFERRED_PROVIDER_iasl}-native" + +PREFERRED_VERSION_refpolicy-mcs = "2.20190201" + +# Select our preferred providers +PREFERRED_PROVIDER_sysvinit-inittab = "sysvinit" +PREFERRED_PROVIDER_virtual/java-initial = "cacao-initial" +PREFERRED_PROVIDER_virtual/java-initial-native = "cacao-initial-native" +PREFERRED_PROVIDER_virtual/java-native = "jamvm-native" +PREFERRED_PROVIDER_virtual/javac-native = "ecj-bootstrap-native" +PREFERRED_PROVIDER_jpeg-native = "jpeg-native" + +# Set the preferred version to C xenstored from xen-tools +PREFERRED_PROVIDER_virtual/xenstored = "xen-tools" +PREFERRED_RPROVIDER_virtual/xenstored = "xen-tools-xenstored" +# Force exclusion of the OCaml xenstored since the above preferences +# are not sufficient to override that as the default selection: +PACKAGE_EXCLUDE += " xen-ocaml-libs-xenstored" + +# The C and OCaml xenstored packages can be installed together +# and this whitelisting is necessary to allow both to be built +MULTI_PROVIDER_WHITELIST += " virtual/xenstored" + +# Default to rsyslog recipe which RPROVIDES rsyslog-conf +# Dom0 and Installer install rsyslog-conf-dom0 instead. +PREFERRED_RPROVIDER_rsyslog-conf = "rsyslog" + +# Default to lvm2 recipe which RPROVIDES lvm2-conf +# Initramfs and installer install lvm2-conf-initramfs and lvm2-conf-installer. +PREFERRED_RPROVIDER_lvm2-conf = "lvm2" + +# Enable tui for GDB by default. This makes it easier to debug small things +# using the gdb ipk. +PACKAGECONFIG_append_pn-gdb = " tui" + +# rpcgen staging and install paths. +require xc-rpcgen.inc + +FILESYSTEM_PERMS_TABLES = "files/openxt-fs-perms.txt" + +# Declare the MACHINE type and KERNEL image name for stubdomains +STUBDOMAIN_MACHINE ?= "openxt-stubdom" +STUBDOMAIN_KERNEL ?= "bzImage" + +# Set our root home +ROOT_HOME = "/root" + +# multilib is required for building Xen's hvmloader, which needs +# materials from a 32-bit libc +require conf/multilib.conf +MULTILIBS = "multilib:lib32" +DEFAULTTUNE_virtclass-multilib-lib32 = "x86" + +# multilib directory settings : 64-bit in /lib, 32-bit in /lib32 +# as required by the OpenXT haskell toolchain +BASE_LIB_tune-core2-32 = "lib32" +BASE_LIB_tune-core2-32 = "lib32" +BASE_LIB_tune-i586 = "lib32" +BASE_LIB_tune-i686 = "lib32" +BASE_LIB_tune-x86 = "lib32" + +BASE_LIB_tune-x86-64 = "lib" +BASE_LIB_tune-x86-64 = "lib" +BASE_LIB_tune-core2-64 = "lib" + +BASE_LIB_tune-core2-64-x32 = "libx32" +BASE_LIB_tune-x86-64-x32 = "libx32" diff --git a/conf/layer.conf b/conf/layer.conf index 4e9fe63670..1a9b0e9676 100644 --- a/conf/layer.conf +++ b/conf/layer.conf @@ -10,6 +10,7 @@ BBMASK = " \ meta-virtualization/recipes-extended/images/xen-guest-image-minimal.bb \ meta-virtualization/recipes-devtools/go/go-build_git.bb \ meta-virtualization/recipes-core/runx/runx_git.bb \ + meta-virtualization/recipes-kernel/linux/linux-%.bbappend \ " # We have a recipes directory, add to BBFILES diff --git a/conf/machine/openxt-common.conf b/conf/machine/openxt-common.conf new file mode 100644 index 0000000000..1ed420ae09 --- /dev/null +++ b/conf/machine/openxt-common.conf @@ -0,0 +1,7 @@ +require conf/machine/include/tune-core2.inc + +DEFAULTTUNE = "core2-64" + +KERNEL_IMAGETYPE = "bzImage" + +MACHINE_FEATURES_BACKFILL_CONSIDERED += "rtc" diff --git a/conf/machine/openxt-dom0.conf b/conf/machine/openxt-dom0.conf new file mode 100644 index 0000000000..2df54b2c9a --- /dev/null +++ b/conf/machine/openxt-dom0.conf @@ -0,0 +1,31 @@ +#@TYPE: Machine +#@NAME: xenclient-dom0 +#@DESCRIPTION: Machine configuration for OpenXT dom0. + +require openxt-common.conf + +MACHINE_FEATURES = " \ + acpi \ + ethernet \ + ext2 \ + keyboard \ + pci \ + rtc \ + screen \ + usbhost \ + x86 \ +" + +KERNEL_MODULE_AUTOLOAD += " \ + xen-acpi-processor \ + xen-gntalloc \ + xen-gntdev \ + xen-pciback \ + xen-netfront \ +" + +# Use OpenXT Linux patched kernel. +PREFERRED_PROVIDER_virtual/kernel = "linux-yocto-openxt-dom0" + +# Use ivc2/ivcdaemon +PREFERRED_PROVIDER_virtual/libivc = "libivc2" diff --git a/conf/machine/openxt-live-installer.conf b/conf/machine/openxt-live-installer.conf new file mode 100644 index 0000000000..08cb908b5e --- /dev/null +++ b/conf/machine/openxt-live-installer.conf @@ -0,0 +1,23 @@ +# Copyright (C) 2010 Citrix Systems +# Copyright (C) 2018 AIS +# Released under the MIT license (see packages/COPYING) +#@TYPE: Machine +#@NAME: openxt-installer +#@DESCRIPTION: Machine configuration for OpenXT installer + +require xenclient-common.conf + +MACHINE_FEATURES = " \ + acpi \ + ethernet \ + ext2 \ + keyboard \ + pci \ + rtc \ + screen \ + usbhost \ + x86 \ +" + +# Use OpenXT Linux patched kernel. +PREFERRED_PROVIDER_virtual/kernel = "linux-yocto-openxt-installer" diff --git a/conf/machine/openxt-ndvm.conf b/conf/machine/openxt-ndvm.conf new file mode 100644 index 0000000000..376383c775 --- /dev/null +++ b/conf/machine/openxt-ndvm.conf @@ -0,0 +1,26 @@ +#@TYPE: Machine +#@NAME: openxt-ndvm +#@DESCRIPTION: Machine configuration for OpenXT NDVM. + +require openxt-common.conf + +MACHINE_FEATURES = " \ + ethernet \ + ext2 \ + pci \ + serial \ + x86 \ +" + +APPEND = "root=/dev/xvda2 ro console=hvc0 iommu=soft" + +USE_VT = "0" + +KERNEL_MODULE_AUTOLOAD += " \ + xen-gntalloc \ + xen-gntdev \ + xen-netback \ +" + +# Use OpenXT Linux patched kernel. +PREFERRED_PROVIDER_virtual/kernel = "linux-yocto-openxt-ndvm" diff --git a/conf/machine/openxt-stubdom.conf b/conf/machine/openxt-stubdom.conf new file mode 100644 index 0000000000..64f69c97d9 --- /dev/null +++ b/conf/machine/openxt-stubdom.conf @@ -0,0 +1,26 @@ +#@TYPE: Machine +#@NAME: openxt-stubdom +#@DESCRIPTION: Machine configuration for OpenXT stub-domain. + +require openxt-common.conf + +MACHINE_FEATURES = " \ + ethernet \ + ext2 \ + pci \ + serial \ + x86 \ +" + +USE_VT = "0" + +KERNEL_MODULE_AUTOLOAD += " \ + xen-gntalloc \ + xen-gntdev \ +" + +# Use OpenXT Linux patched kernel. +PREFERRED_PROVIDER_virtual/kernel = "linux-yocto-openxt-stubdom" + +# Use /dev/ivc. +PREFERRED_PROVIDER_virtual/libivc = "libivc" diff --git a/conf/machine/openxt-uivm.conf b/conf/machine/openxt-uivm.conf new file mode 100644 index 0000000000..fd04c8e308 --- /dev/null +++ b/conf/machine/openxt-uivm.conf @@ -0,0 +1,24 @@ +#@TYPE: Machine +#@NAME: openxt-uivm +#@DESCRIPTION: Machine configuration for OpenXT UIVM. + +require openxt-common.conf + +MACHINE_FEATURES = " \ + ethernet \ + ext2 \ + screen \ + serial \ + x86 \ +" + +USE_VT = "0" + +KERNEL_MODULE_AUTOLOAD += " \ + xen-gntalloc \ + xen-gntdev \ + openxtfb \ +" + +# Use OpenXT Linux patched kernel. +PREFERRED_PROVIDER_virtual/kernel = "linux-yocto-openxt-uivm" diff --git a/recipes-core/base-files/base-files_3.%.bbappend b/recipes-core/base-files/base-files_3.%.bbappend index 52f72318e8..03d39232b7 100644 --- a/recipes-core/base-files/base-files_3.%.bbappend +++ b/recipes-core/base-files/base-files_3.%.bbappend @@ -31,6 +31,10 @@ dirs755_append_xenclient-dom0 = " \ /storage \ ${localstatedir}/cores \ " +dirs755_append_openxt-dom0 = " \ + /storage \ + ${localstatedir}/cores \ +" # OpenXT: UIVM has only root as user, pre-create local conf directories. dirs755_append_xenclient-uivm = " \ /root/.gconf \ @@ -38,6 +42,12 @@ dirs755_append_xenclient-uivm = " \ /root/.cache \ /root/.ssh \ " +dirs755_append_openxt-uivm = " \ + /root/.gconf \ + /root/.gnome2 \ + /root/.cache \ + /root/.ssh \ +" volatiles = "" conffiles = " \ diff --git a/recipes-core/base-files/files/openxt-dom0/fstab b/recipes-core/base-files/files/openxt-dom0/fstab new file mode 100644 index 0000000000..bed1c4c49d --- /dev/null +++ b/recipes-core/base-files/files/openxt-dom0/fstab @@ -0,0 +1,45 @@ +# proc is presumably mounted by /etc/init.d/rcS script. +# /etc/init.d/rcS might use this file, so match this entry with +# /etc/fstab.early. +proc /proc proc nosuid,noexec,nodev 0 0 + +# OpenXT read-only root tmpfs: +# These have to be either absent from this file or match /etc/fstab.early +# exactly for mountearly.sh and mountall.sh to work correctly. +sysfs /sys sysfs nosuid,noexec,nodev 0 0 +devtmpfs /dev devtmpfs mode=0755,nosuid 0 0 +tmpfs /run tmpfs defaults,rootcontext=system_u:object_r:var_run_t:s0,size=5M 0 0 +tmpfs /tmp tmpfs defaults,rootcontext=system_u:object_r:tmp_t:s0,size=100M 0 0 + +tmpfs /var/volatile tmpfs defaults,rootcontext=system_u:object_r:var_t:s0,size=2M 0 0 +tmpfs /var/cache tmpfs defaults,rootcontext=system_u:object_r:var_t:s0,size=100M 0 0 + +# OpenXT read-only root: +# mountall.sh should take care of these. +rootfs / auto defaults,ro,noatime 1 1 + +securityfs /sys/kernel/security securityfs defaults 0 0 + +devpts /dev/pts devpts mode=0620,gid=5 0 0 +tmpfs /dev/shm tmpfs mode=0777,size=1M 0 0 + +xenfs /proc/xen xenfs defaults 0 0 + +tmpfs /var/lib/ovf tmpfs defaults,rootcontext=system_u:object_r:xc_ovf_var_lib_t:s0,size=100M 0 0 +tmpfs /var/lib/dbus tmpfs defaults,rootcontext=system_u:object_r:system_dbusd_var_lib_t:s0,size=1M 0 0 +tmpfs /var/lib/xen tmpfs defaults,rootcontext=system_u:object_r:xend_var_lib_t:s0,size=1M 0 0 + +tmpfs /root/.ssh tmpfs defaults,rootcontext=system_u:object_r:ssh_home_t:s0,size=1M 0 0 +tmpfs /mnt/upgrade tmpfs defaults,size=1M 0 0 +ramfs /mnt/secure ramfs context=system_u:object_r:xc_secure_t:s0,size=1M 0 0 + +/dev/mapper/log /var/log ext4 errors=remount-ro,noatime 1 2 +/dev/mapper/cores /var/cores ext4 errors=remount-ro,noatime,rootcontext=system_u:object_r:var_core_t:s0 1 3 +/dev/mapper/xenclient-boot /boot/system ext4 errors=remount-ro,noatime 1 4 +/dev/mapper/xenclient-storage /storage ext4 errors=remount-ro,user_xattr,noatime 1 5 +/dev/mapper/swap none swap sw 0 0 + +# OpenXT: The following mount will fail on non-UEFI installs. +# For some reason, at boot time, that usually results in the rest of this file getting ignored. +# Having it be the last one makes it a non-issue. +efivarfs /sys/firmware/efi/efivars efivarfs ro,nosuid,nodev,noexec,noatime 0 0 diff --git a/recipes-core/base-files/files/openxt-live-installer/fstab b/recipes-core/base-files/files/openxt-live-installer/fstab new file mode 100644 index 0000000000..64b9e79f37 --- /dev/null +++ b/recipes-core/base-files/files/openxt-live-installer/fstab @@ -0,0 +1,12 @@ +proc /proc proc nosuid,noexec,nodev 0 0 + +sysfs /sys sysfs nosuid,noexec,nodev 0 0 +devtmpfs /dev devtmpfs mode=0755,nosuid 0 0 +devpts /dev/pts devpts mode=0620,gid=5 0 0 + +rootfs / auto rw,defaults,noatime 1 1 + +securityfs /sys/kernel/security securityfs defaults 0 0 +xenfs /proc/xen xenfs defaults 0 0 + +efivarfs /sys/firmware/efi/efivars efivarfs rw,nosuid,nodev,noexec,noatime,nofail 0 0 diff --git a/recipes-core/base-files/files/openxt-ndvm/fstab b/recipes-core/base-files/files/openxt-ndvm/fstab new file mode 100644 index 0000000000..2942324bc4 --- /dev/null +++ b/recipes-core/base-files/files/openxt-ndvm/fstab @@ -0,0 +1,37 @@ +# proc is presumably mounted by /etc/init.d/rcS script. +# /etc/init.d/rcS might use this file, so match this entry with +# /etc/fstab.early. +proc /proc proc nosuid,noexec,nodev 0 0 + +# OpenXT read-only root tmpfs: +# These have to be either absent from this file or match /etc/fstab.early +# exactly for mountearly.sh and mountall.sh to work correctly. +sysfs /sys sysfs nosuid,noexec,nodev 0 0 +devtmpfs /dev devtmpfs mode=0755,nosuid 0 0 +tmpfs /run tmpfs defaults,rootcontext=system_u:object_r:var_run_t:s0,size=5M 0 0 +tmpfs /tmp tmpfs defaults,rootcontext=system_u:object_r:tmp_t:s0,size=100M 0 0 + +tmpfs /var/volatile tmpfs defaults,rootcontext=system_u:object_r:var_t:s0,size=2M 0 0 +tmpfs /var/cache tmpfs defaults,rootcontext=system_u:object_r:var_t:s0,size=100M 0 0 + +# OpenXT read-only root: +# mountall.sh should take care of these. +rootfs / auto defaults,ro,noatime 1 1 + +devpts /dev/pts devpts mode=0620,gid=5 0 0 +tmpfs /dev/shm tmpfs mode=0777,size=1M 0 0 + +xenfs /proc/xen xenfs defaults 0 0 + +tmpfs /var/log tmpfs defaults,rootcontext=system_u:object_r:var_log_t:s0,size=10M 0 0 +tmpfs /var/lib/dbus tmpfs defaults,rootcontext=system_u:object_r:system_dbusd_var_lib_t:s0,size=1M 0 0 +tmpfs /var/lib/dhcp tmpfs defaults,rootcontext=system_u:object_r:dhcp_state_t:s0,size=1M 0 0 +tmpfs /var/lib/NetworkManager tmpfs defaults,rootcontext=system_u:object_r:NetworkManager_var_lib_t:s0,size=1M 0 0 + +tmpfs /media/ram tmpfs defaults,size=1M 0 0 + +tmpfs /etc/NetworkManager tmpfs defaults,rootcontext=system_u:object_r:NetworkManager_etc_t:s0,size=2M 0 0 +tmpfs /etc/dnsmasq-config tmpfs defaults,rootcontext=system_u:object_r:dnsmasq_etc_t:s0,size=1M 0 0 +tmpfs /etc/iproute2 tmpfs defaults,rootcontext=system_u:object_r:net_conf_t:s0,size=1M 0 0 + +/dev/xvdb none swap sw 0 0 diff --git a/recipes-core/base-files/files/openxt-uivm/fstab b/recipes-core/base-files/files/openxt-uivm/fstab new file mode 100644 index 0000000000..e816bdbe6d --- /dev/null +++ b/recipes-core/base-files/files/openxt-uivm/fstab @@ -0,0 +1,36 @@ +# proc is presumably mounted by /etc/init.d/rcS script. +# /etc/init.d/rcS might use this file, so match this entry with +# /etc/fstab.early. +proc /proc proc nosuid,noexec,nodev 0 0 + +# OpenXT read-only root tmpfs: +# These have to be either absent from this file or match /etc/fstab.early +# exactly for mountearly.sh and mountall.sh to work correctly. +sysfs /sys sysfs nosuid,noexec,nodev 0 0 +devtmpfs /dev devtmpfs mode=0755,nosuid 0 0 +tmpfs /run tmpfs defaults,size=5M 0 0 +tmpfs /tmp tmpfs defaults,size=100M 0 0 + +# OpenXT read-only root: +# mountall.sh should take care of these. +rootfs / auto defaults,ro,noatime 1 1 + +devpts /dev/pts devpts mode=0620,gid=5 0 0 +tmpfs /dev/shm tmpfs mode=0777,size=1M 0 0 + +tmpfs /var/volatile tmpfs defaults,size=2M 0 0 +tmpfs /var/cache tmpfs defaults,size=100M 0 0 +tmpfs /var/log tmpfs defaults,size=10M 0 0 +tmpfs /var/lib/dbus tmpfs defaults,size=1M 0 0 + +tmpfs /media/ram tmpfs defaults,size=1M 0 0 + +# TODO: Could be handled with volatiles? +tmpfs /root/.gconf tmpfs defaults,size=10M 0 0 +tmpfs /root/.ssh tmpfs defaults,size=1M 0 0 +tmpfs /root/.cache tmpfs defaults,size=1M 0 0 +tmpfs /var/lib/NetworkManager tmpfs defaults,size=1M 0 0 + +xenfs /proc/xen xenfs defaults 0 0 + +/dev/xvda2 none swap sw 0 0 diff --git a/recipes-core/base-files/files/openxt-uivm/fstab.early b/recipes-core/base-files/files/openxt-uivm/fstab.early new file mode 100644 index 0000000000..378d766d1c --- /dev/null +++ b/recipes-core/base-files/files/openxt-uivm/fstab.early @@ -0,0 +1,15 @@ +# proc is presumably mounted by /etc/init.d/rcS script. +# /etc/init.d/rcS might use /etc/fstab when not modified accordingly, so match +# this entry with /etc/fstab. +proc /proc proc nosuid,noexec,nodev 0 0 + +# OpenXT read-only root tmpfs: +# These have to be either absent from this file or match /etc/fstab exactly for +# mountearly.sh and mountall.sh to work correctly. +sysfs /sys sysfs nosuid,noexec,nodev 0 0 +devtmpfs /dev devtmpfs mode=0755,nosuid 0 0 +tmpfs /run tmpfs defaults,size=5M 0 0 +tmpfs /tmp tmpfs defaults,size=100M 0 0 + +tmpfs /var/volatile tmpfs defaults,size=2M 0 0 +tmpfs /var/cache tmpfs defaults,size=100M 0 0 diff --git a/recipes-core/images/openxt-dom0-image.bb b/recipes-core/images/openxt-dom0-image.bb new file mode 100644 index 0000000000..ffbd83786d --- /dev/null +++ b/recipes-core/images/openxt-dom0-image.bb @@ -0,0 +1,119 @@ +# XenClient dom0 image. + +LICENSE = "GPLv2 & MIT" +LIC_FILES_CHKSUM = " \ + file://${COMMON_LICENSE_DIR}/GPL-2.0;md5=801f80980d171dd6425610833a22dbe6 \ + file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302 \ +" + +inherit openxt-selinux-image +inherit openxt-vm-common + +INITRD_VM = "openxt-dom0-initramfs-image" +INSTALL_VM_INITRD = "1" + +IMAGE_FEATURES += " \ + package-management \ + read-only-rootfs \ + root-bash-shell \ + wildcard-sshd-argo \ + allow-root-login \ +" +IMAGE_FSTYPES = "ext3.gz" +export IMAGE_BASENAME = "openxt-dom0-image" + +COMPATIBLE_MACHINE = "(openxt-dom0)" + + +# xserver-xorg should not live in dom0, but UIVM. +BAD_RECOMMENDATIONS += " \ + xserver-xorg \ + avahi-daemon \ + avahi-autoipd \ + ${@bb.utils.contains('IMAGE_FEATURES', 'web-certificates', '', 'ca-certificates', d)} \ + libivc \ +" + +IMAGE_INSTALL += "\ + initscripts \ + packagegroup-core-boot \ + packagegroup-base \ + packagegroup-xenclient-common \ + packagegroup-xenclient-dom0 \ + packagegroup-openxt-test \ + argo-module \ + xenclient-preload-hs-libs \ + linux-firmware-i915 \ + devicemodel-stubdom \ + ${@bb.utils.contains('IMAGE_FEATURES', 'debug-tweaks', 'packagegroup-selinux-policycoreutils audit', '' ,d)} \ +" + +inherit xenclient-licences + +require xenclient-version.inc + +post_rootfs_shell_commands() { + mkdir -p ${IMAGE_ROOTFS}/config/etc + mv ${IMAGE_ROOTFS}/etc/passwd ${IMAGE_ROOTFS}/config/etc + mv ${IMAGE_ROOTFS}/etc/shadow ${IMAGE_ROOTFS}/config/etc + ln -s ../config/etc/passwd ${IMAGE_ROOTFS}/etc/passwd + ln -s ../config/etc/shadow ${IMAGE_ROOTFS}/etc/shadow + ln -s ../config/etc/.pwd.lock ${IMAGE_ROOTFS}/etc/.pwd.lock + + rm ${IMAGE_ROOTFS}/etc/hosts + ln -s /var/run/hosts ${IMAGE_ROOTFS}/etc/hosts + ln -s /var/volatile/etc/resolv.conf ${IMAGE_ROOTFS}/etc/resolv.conf + + echo 'kernel.printk_ratelimit = 0' >> ${IMAGE_ROOTFS}/etc/sysctl.conf + + # Create mountpoint for /mnt/secure + mkdir -p ${IMAGE_ROOTFS}/mnt/secure + + # Create mountpoint for /mnt/upgrade + mkdir -p ${IMAGE_ROOTFS}/mnt/upgrade + + # Create mountpoint for boot/system + mkdir -p ${IMAGE_ROOTFS}/boot/system + + # Create XL-related files and directories + mkdir -p ${IMAGE_ROOTFS}/var/lib/xen + mkdir -p ${IMAGE_ROOTFS}/etc/xen + touch ${IMAGE_ROOTFS}/etc/xen/xl.conf + + # Write coredumps in /var/cores + echo 'kernel.core_pattern = /var/cores/%e-%t.%p.core' >> ${IMAGE_ROOTFS}/etc/sysctl.conf +} +ROOTFS_POSTPROCESS_COMMAND += "post_rootfs_shell_commands; " + +# Get rid of unneeded initscripts +remove_initscripts() { + remove_initscript "rmnologin.sh" + remove_initscript "finish.sh" +} +ROOTFS_POSTPROCESS_COMMAND += "remove_initscripts; " + +# After ensuring that the correct number of xenstored daemon(s) are installed, +# enforce that the init script is active: +activate_xenstored_initscript() { + update-rc.d -r ${IMAGE_ROOTFS} xenstored defaults 05 +} +ROOTFS_POSTPROCESS_COMMAND += "activate_xenstored_initscript; " + +# Handle required configuration of the rootfs to store persistent files on +# encripted /config partition. +rw_config_partition() { + # If we are using openssh but want the persistent data to be stored in the + # encrypted config partition, replace or append SYSCONFDIR in + # /etc/default/ssh. + # This should only be done after read_only_rootfs_hook(s) have been done. + if [ -d ${IMAGE_ROOTFS}${sysconfdir}/ssh ]; then + sed -i -e '/^SYSCONFDIR=/{h;s/=.*/=\$\{SYSCONFDIR:-\/config\/etc\/ssh\}/};${x;/^$/{s//SYSCONFDIR=\$\{SYSCONFDIR:-\/config\/etc\/ssh\}/;H};x}' ${IMAGE_ROOTFS}${sysconfdir}/default/ssh + sed -i -e 's/HostKey .*\/ssh\/ssh_host_\(.*\)key/HostKey \/config\/etc\/ssh\/ssh_host_\1key/' ${IMAGE_ROOTFS}${sysconfdir}/ssh/sshd_config_readonly + echo "HostKey /config/etc/ssh/ssh_host_dsa_key" >> ${IMAGE_ROOTFS}${sysconfdir}/ssh/sshd_config + echo "HostKey /config/etc/ssh/ssh_host_rsa_key" >> ${IMAGE_ROOTFS}${sysconfdir}/ssh/sshd_config + echo "HostKey /config/etc/ssh/ssh_host_ecdsa_key" >> ${IMAGE_ROOTFS}${sysconfdir}/ssh/sshd_config + echo "HostKey /config/etc/ssh/ssh_host_ed25519_key" >> ${IMAGE_ROOTFS}${sysconfdir}/ssh/sshd_config + fi +} +ROOTFS_POSTPROCESS_COMMAND += "rw_config_partition; " +ROOTFS_POSTPROCESS_COMMAND += "start_tty_on_hvc0;" diff --git a/recipes-core/images/openxt-dom0-initramfs-image.bb b/recipes-core/images/openxt-dom0-initramfs-image.bb new file mode 100644 index 0000000000..60b1c2962f --- /dev/null +++ b/recipes-core/images/openxt-dom0-initramfs-image.bb @@ -0,0 +1,40 @@ +SUMMARY = "Initramfs image for OpenXT dom0" +DESCRIPTION = "Initramfs image containing the early boot components required to \ +bootsrap OpenXT dom0." +LICENSE = "GPLv2 & MIT" +LIC_FILES_CHKSUM = " \ + file://${COMMON_LICENSE_DIR}/GPL-2.0;md5=801f80980d171dd6425610833a22dbe6 \ + file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302 \ +" +COMPATIBLE_MACHINE = "(openxt-dom0)" + +IMAGE_FSTYPES = "cpio.gz" +IMAGE_INSTALL = " \ + busybox \ + initramfs-module-functions \ + initramfs-module-lvm \ + initramfs-module-udev \ + initramfs-module-bootfs \ + initramfs-module-tpm \ + initramfs-module-tpm2 \ + initramfs-module-selinux \ +" +IMAGE_LINGUAS = "en-us" + +inherit image + +NO_RECOMMENDATIONS = "1" +BAD_RECOMMENDATIONS += " \ + ldconfig \ + busybox-syslog \ + busybox-udhcpc \ +" + +PACKAGE_REMOVE = " \ + kernel-image-* \ +" +post_rootfs_shell_commands() { + rm -f ${IMAGE_ROOTFS}/sbin/udhcpc; + rm -rvf ${IMAGE_ROOTFS}/usr/lib/opkg; +} +ROOTFS_POSTPROCESS_COMMAND += " post_rootfs_shell_commands; " diff --git a/recipes-core/images/openxt-live-installer-image.bb b/recipes-core/images/openxt-live-installer-image.bb new file mode 100644 index 0000000000..1d1ff6bb3d --- /dev/null +++ b/recipes-core/images/openxt-live-installer-image.bb @@ -0,0 +1,102 @@ +# Part 1 of the XenClient host installer. +# +# This is responsible for retrieving the XenClient repository and extracting +# and running part 2 of the host installer, which contains the logic to install +# or upgrade a specific version of XenClient. + +LICENSE = "GPLv2 & MIT" +LIC_FILES_CHKSUM = " \ + file://${COMMON_LICENSE_DIR}/GPL-2.0;md5=801f80980d171dd6425610833a22dbe6 \ + file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302 \ +" + +PR = "r16" + +IMAGE_FSTYPES = "cpio.gz" +export IMAGE_BASENAME = "openxt-live-installer-image" + +COMPATIBLE_MACHINE = "(openxt-live-installer)" + +BAD_RECOMMENDATIONS += " \ + ${@bb.utils.contains('IMAGE_FEATURES', 'web-certificates', '', 'ca-certificates', d)} \ +" + +INITSCRIPT_REMOVE = " \ + blktap \ + sshd-argo \ +" + +IMAGE_FEATURES += " \ + empty-root-password \ + root-bash-shell \ +" + +IMAGE_INSTALL = "\ + initscripts \ + packagegroup-core-boot \ + packagegroup-base \ + packagegroup-xenclient-common \ + packagegroup-xenclient-installer \ + linux-firmware-iwlwifi \ + linux-firmware-bnx2 \ + linux-firmware-i915 \ + linux-firmware-nvidia \ + linux-firmware-radeon \ + libdrm-nouveau \ + libdrm-radeon \ +" +# The entire installer rootfs is passed as the initramfs. +# Inflate the maximum value to 512M to reflect that (original definition is +# 128M in bitbake.conf) +INITRAMFS_MAXSIZE = "524288" + +inherit openxt-image +inherit xenclient-licences + +require xenclient-version.inc + +post_rootfs_shell_commands() { + # Create /init symlink + ln -s sbin/init ${IMAGE_ROOTFS}/init; + + # Update /etc/inittab + sed -i '/^1:/d' ${IMAGE_ROOTFS}/etc/inittab; + { + echo '1:2345:once:/install/part1/autostart-main < /dev/tty1 > /dev/tty1'; + echo '2:2345:respawn:/usr/bin/tail -F /var/log/installer > /dev/tty2'; + echo '3:2345:respawn:/sbin/getty 38400 tty3'; + echo '4:2345:respawn:/usr/bin/tail -F /var/log/messages > /dev/tty4'; + echo '5:2345:respawn:/sbin/getty 38400 tty5'; + echo '6:2345:respawn:/sbin/getty 38400 tty6'; + echo '7:2345:respawn:/install/part1/autostart-status < /dev/tty7 > /dev/tty7'; + echo 'ca::ctrlaltdel:/sbin/reboot'; + echo 'S0:12345:respawn:/sbin/getty 115200 ttyS0'; + } >> ${IMAGE_ROOTFS}/etc/inittab; + + # Update /etc/network/interfaces + { + echo 'auto lo'; + echo 'iface lo inet loopback'; + } > ${IMAGE_ROOTFS}/etc/network/interfaces; + + # Password files are expected in /config + mkdir -p ${IMAGE_ROOTFS}/config/etc; + mv ${IMAGE_ROOTFS}/etc/shadow ${IMAGE_ROOTFS}/config/etc/shadow; + mv ${IMAGE_ROOTFS}/etc/passwd ${IMAGE_ROOTFS}/config/etc/passwd; + ln -s /config/etc/shadow ${IMAGE_ROOTFS}/etc/shadow; + ln -s /config/etc/passwd ${IMAGE_ROOTFS}/etc/passwd; + + # Create file to identify this as the host installer filesystem + touch ${IMAGE_ROOTFS}/etc/xenclient-host-installer; +} +ROOTFS_POSTPROCESS_COMMAND += "post_rootfs_shell_commands; " +ROOTFS_POSTPROCESS_COMMAND += "start_tty_on_hvc0; " + +# Install Xen in the installer image. +# This is a legacy procedure as the installer does not require Xen to run, +# presumably this was done so that users would know immediately before +# installing that Xen cannot be run on the hardware. +xen_install() { + cp -f ${IMAGE_ROOTFS}/boot/xen.gz ${DEPLOY_DIR_IMAGE}/ +} +IMAGE_POSTPROCESS_COMMAND += "xen_install; " diff --git a/recipes-core/images/openxt-ndvm-image.bb b/recipes-core/images/openxt-ndvm-image.bb new file mode 100644 index 0000000000..900291bbd1 --- /dev/null +++ b/recipes-core/images/openxt-ndvm-image.bb @@ -0,0 +1,88 @@ +# XenClient Network VM image. + +LICENSE = "GPLv2 & MIT" +LIC_FILES_CHKSUM = " \ + file://${COMMON_LICENSE_DIR}/GPL-2.0;md5=801f80980d171dd6425610833a22dbe6 \ + file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302 \ +" + +inherit openxt-selinux-image + +IMAGE_FEATURES += " \ + package-management \ + read-only-rootfs \ + empty-root-password \ + root-bash-shell \ +" + +IMAGE_FSTYPES = "ext3.disk.vhd.gz" +export IMAGE_BASENAME = "openxt-ndvm-image" + +COMPATIBLE_MACHINE = "(openxt-ndvm)" + + +BAD_RECOMMENDATIONS += " \ + avahi-daemon \ + avahi-autoipd \ + ca-certificates \ +" +# List of packages that should not be installed +PACKAGE_REMOVE = " \ + hicolor-icon-theme \ +" + +IMAGE_FEATURES += "empty-root-password" + +INITSCRIPT_REMOVE = " \ + urandom \ + sshd \ +" + +IMAGE_INSTALL = " \ + ${ROOTFS_PKGMANAGE} \ + packagegroup-core-boot \ + packagegroup-base \ + packagegroup-xenclient-common \ + util-linux-mount \ + util-linux-umount \ + openssh \ + kernel-modules \ + libargo \ + libargo-bin \ + dbus \ + xenclient-dbusbouncer \ + networkmanager \ + linux-firmware-iwlwifi \ + linux-firmware-bnx2 \ + bridge-utils \ + iptables \ + xenclient-ndvm-tweaks \ + rsyslog \ + argo-module \ + xen-tools-libxenstore \ + xen-tools-xenstore \ + wget \ + ethtool \ + carrier-detect \ + xenclient-nws \ + modemmanager \ + ppp \ + iputils-ping \ + dbd-tools-vm \ + xen-vif-scripts-ndvm \ +" + +require xenclient-version.inc +inherit xenclient-licences + +post_rootfs_shell_commands() { + # Trick to resolve dom0 name with argo. + echo '1.0.0.0 dom0' >> ${IMAGE_ROOTFS}/etc/hosts; + + # enable ctrlaltdel reboot because PV driver uses ctrl+alt+del to interpret reboot issued via xenstore + echo 'ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now' >> ${IMAGE_ROOTFS}/etc/inittab; + + # NDVM doesn't have a /dev/tty1, disable the login shell on it + sed -i 's/[^#].*getty.*tty1$/#&/' ${IMAGE_ROOTFS}/etc/inittab ; +} +ROOTFS_POSTPROCESS_COMMAND += "post_rootfs_shell_commands; " diff --git a/recipes-core/images/openxt-stubdom-initramfs-image.bb b/recipes-core/images/openxt-stubdom-initramfs-image.bb new file mode 100644 index 0000000000..5073e6249f --- /dev/null +++ b/recipes-core/images/openxt-stubdom-initramfs-image.bb @@ -0,0 +1,45 @@ +# Stubdomain initramfs image. + +LICENSE = "GPLv2 & MIT" +LIC_FILES_CHKSUM = " \ + file://${COMMON_LICENSE_DIR}/GPL-2.0;md5=801f80980d171dd6425610833a22dbe6 \ + file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302 \ +" + +IMAGE_FSTYPES = "cpio.gz" + +COMPATIBLE_MACHINE = "(openxt-stubdom)" + +BAD_RECOMMENDATIONS += " \ + libivc2 \ +" + +IMAGE_INSTALL = " \ + busybox \ + bridge-utils \ + initramfs-stubdomain \ + xen-tools-xenstore \ + qemu-dm-stubdom \ + argo-module \ + kernel-modules \ +" +IMAGE_LINGUAS = "" + +# List of packages removed at rootfs-postprocess. +# - Remove any kernel-image that the kernel-module-* packages may have pulled in. +# - Remove udev (use busybox-mdev instead, this is a simple initramfs). +# - Remove sysvinit (no need for init management). +PACKAGE_REMOVE = " \ + kernel-image-* \ + udev \ + sysvinit \ +" + +inherit openxt-image + +post_rootfs_shell_commands() { + rm -f ${IMAGE_ROOTFS}/sbin/udhcpc; + rm -f ${IMAGE_ROOTFS}/sbin/ldconfig; + rm -rvf ${IMAGE_ROOTFS}/usr/lib/opkg; +} +ROOTFS_POSTPROCESS_COMMAND += " post_rootfs_shell_commands; " diff --git a/recipes-core/images/openxt-uivm-image.bb b/recipes-core/images/openxt-uivm-image.bb new file mode 100644 index 0000000000..6fdad0a2e7 --- /dev/null +++ b/recipes-core/images/openxt-uivm-image.bb @@ -0,0 +1,115 @@ +# XenClient UIVM image + +LICENSE = "GPLv2 & MIT" +LIC_FILES_CHKSUM = " \ + file://${COMMON_LICENSE_DIR}/GPL-2.0;md5=801f80980d171dd6425610833a22dbe6 \ + file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302 \ +" + +inherit openxt-image + +IMAGE_FEATURES += " \ + package-management \ + read-only-rootfs \ + empty-root-password \ + root-bash-shell \ +" +IMAGE_FSTYPES = "ext3.vhd.gz" +export IMAGE_BASENAME = "openxt-uivm-image" + +COMPATIBLE_MACHINE = "(openxt-uivm)" + + +BAD_RECOMMENDATIONS += " \ + avahi-daemon \ + avahi-autoipd \ +" + +INITSCRIPT_REMOVE = " \ + finish.sh \ + rmnologin.sh \ + sshd \ + urandom \ + networking \ +" + +# Specifies the list of locales to install into the image during the root +# filesystem construction process. +# http://www.yoctoproject.org/docs/current/ref-manual/ref-manual.html#var-IMAGE_LINGUAS +IMAGE_LINGUAS = " \ + en-us \ +" + +# Refine xserver packages installed by packagegroup-core-x11-xserver. +XSERVER = " \ + xserver-xorg \ + xf86-input-evdev \ + xf86-input-mouse \ + xf86-input-keyboard \ + xf86-video-openxtfb \ +" + +IMAGE_INSTALL += "\ + ${XSERVER} \ + packagegroup-xenclient-common \ + packagegroup-xenclient-xfce-minimal \ + openssh \ + packagegroup-base \ + kernel-modules \ + argo-module \ + libargo \ + libargo-bin \ + xinit \ + xprop \ + xrandr \ + surf \ + network-manager-applet \ + network-manager-applet-locale-de \ + network-manager-applet-locale-es \ + network-manager-applet-locale-fr \ + network-manager-applet-locale-ja \ + network-manager-applet-locale-zh-cn \ + gnome-keyring-locale-de \ + gnome-keyring-locale-es \ + gnome-keyring-locale-fr \ + gnome-keyring-locale-ja \ + gnome-keyring-locale-zh-cn \ + iso-codes-locale-de \ + iso-codes-locale-es \ + iso-codes-locale-fr \ + iso-codes-locale-ja \ + iso-codes-locale-zh-cn \ + xterm \ + gconf \ + xenclient-uivm-xsessionconfig \ + setxkbmap \ + libx11-locale \ + rsyslog \ + glibc-gconv-libjis \ + glibc-gconv-euc-jp \ + mobile-broadband-provider-info \ + ttf-dejavu-sans \ + ttf-dejavu-sans-mono \ + uim \ + uim-common \ + uim-gtk2.0 \ + anthy \ + matchbox-keyboard \ + matchbox-keyboard-im \ + kernel-module-openxtfb \ +" + +require xenclient-version.inc +inherit xenclient-licences + +post_rootfs_shell_commands() { + # Start WM right away. + echo 'x:5:respawn:/bin/su - root -c /usr/bin/startxfce4' >> ${IMAGE_ROOTFS}/etc/inittab + + # enable ctrlaltdel reboot because PV driver uses ctrl+alt+del to interpret reboot issued via xenstore + echo 'ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now' >> ${IMAGE_ROOTFS}/etc/inittab + + # Trick to resolve dom0 name with argo. + echo '1.0.0.0 dom0' >> ${IMAGE_ROOTFS}/etc/hosts +} +ROOTFS_POSTPROCESS_COMMAND += "post_rootfs_shell_commands; " diff --git a/recipes-core/init-ifupdown/init-ifupdown-1.0/openxt-dom0/interfaces b/recipes-core/init-ifupdown/init-ifupdown-1.0/openxt-dom0/interfaces new file mode 100644 index 0000000000..e9d591b301 --- /dev/null +++ b/recipes-core/init-ifupdown/init-ifupdown-1.0/openxt-dom0/interfaces @@ -0,0 +1,9 @@ +# Configure Loopback +auto lo +iface lo inet loopback + +auto eth0 +iface eth0 inet manual + +auto uivm +iface uivm inet manual diff --git a/recipes-core/init-ifupdown/init-ifupdown-1.0/openxt-ndvm/interfaces b/recipes-core/init-ifupdown/init-ifupdown-1.0/openxt-ndvm/interfaces new file mode 100644 index 0000000000..7cbfb03f8a --- /dev/null +++ b/recipes-core/init-ifupdown/init-ifupdown-1.0/openxt-ndvm/interfaces @@ -0,0 +1,22 @@ +# Configure Loopback +auto lo +iface lo inet loopback + +auto eth0 +iface eth0 inet manual + +auto uivm +iface uivm inet manual + +auto brinternal +iface brinternal inet manual + +auto brshared +iface brshared inet manual + +auto brwireless +iface brwireless inet manual + +auto brbridged +iface brbridged inet dhcp + diff --git a/recipes-core/init-ifupdown/init-ifupdown-1.0/openxt-uivm/interfaces b/recipes-core/init-ifupdown/init-ifupdown-1.0/openxt-uivm/interfaces new file mode 100644 index 0000000000..ed87a0a6b2 --- /dev/null +++ b/recipes-core/init-ifupdown/init-ifupdown-1.0/openxt-uivm/interfaces @@ -0,0 +1,10 @@ +auto lo +iface lo inet loopback + +auto eth0 +iface eth0 inet dhcp +udhcpc_opts -b + +auto eth1 +iface eth1 inet dhcp +udhcpc_opts -b diff --git a/recipes-core/initrdscripts/initramfs-stubdomain/init.sh b/recipes-core/initrdscripts/initramfs-stubdomain/init.sh index 428583a89f..7935a6f524 100755 --- a/recipes-core/initrdscripts/initramfs-stubdomain/init.sh +++ b/recipes-core/initrdscripts/initramfs-stubdomain/init.sh @@ -33,6 +33,12 @@ exec 0< /dev/hvc0 exec 1> /dev/hvc0 exec 2> /dev/hvc0 +modprobe xen-argo +modprobe xen-gntalloc +modprobe xen-gntdev +modprobe xen-netfront +modprobe xen-pcifront + sync mkdir -p /proc /sys /mnt /tmp mount -t proc proc /proc diff --git a/recipes-core/initrdscripts/initramfs-stubdomain_1.0.bb b/recipes-core/initrdscripts/initramfs-stubdomain_1.0.bb index 240fc13c8d..dc47bf5bbc 100644 --- a/recipes-core/initrdscripts/initramfs-stubdomain_1.0.bb +++ b/recipes-core/initrdscripts/initramfs-stubdomain_1.0.bb @@ -2,7 +2,7 @@ DESCRIPTION = "Stubdomain initscript." LICENSE = "MIT" LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302" -COMPATIBLE_MACHINE = "xenclient-stubdomain" +COMPATIBLE_MACHINE = "openxt-stubdom" SRC_URI = " \ file://init.sh \ diff --git a/recipes-core/initscripts/initscripts-1.0/mountall.sh b/recipes-core/initscripts/initscripts-1.0/mountall.sh index ffe4d0d1fd..57ee5b5fe7 100755 --- a/recipes-core/initscripts/initscripts-1.0/mountall.sh +++ b/recipes-core/initscripts/initscripts-1.0/mountall.sh @@ -34,7 +34,7 @@ RESTORECON=/sbin/restorecon # about this. So we mount "proc" filesystems without -v. # test "$VERBOSE" != no && echo "Mounting local filesystems..." -mount -a $MOUNTALL 2>&1 | logger -s -p user.err +mount -a $MOUNTALL 2>&1 # # We might have mounted something over /dev, see if /dev/initctl is there. diff --git a/recipes-core/initscripts/initscripts-1.0/openxt-dom0/mountall.sh b/recipes-core/initscripts/initscripts-1.0/openxt-dom0/mountall.sh new file mode 100755 index 0000000000..0661b6aee8 --- /dev/null +++ b/recipes-core/initscripts/initscripts-1.0/openxt-dom0/mountall.sh @@ -0,0 +1,62 @@ +# +# Copyright (c) 2012 Citrix Systems, Inc. +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +# +# mountall.sh Mount all filesystems. +# +# Version: @(#)mountall.sh 2.83-2 01-Nov-2001 miquels@cistron.nl +# +. /etc/default/rcS +if test -f /etc/default/mountall; then + . /etc/default/mountall +fi + +. /etc/init.d/functions + +mkdir -p /dev/shm /dev/pts +restore /dev/shm /dev/pts + +# Mount local filesystems in /etc/fstab. For some reason, people +# might want to mount "proc" several times, and mount -v complains +# about this. So we mount "proc" filesystems without -v. +# +test "$VERBOSE" != no && echo "Mounting local filesystems..." +mount -a $MOUNTALL 2>&1 | logger -s -p user.err + +# +# We might have mounted something over /dev, see if /dev/initctl is there. +# +if test ! -p /dev/initctl +then + rm -f /dev/initctl + mknod -m 600 /dev/initctl p + restore /dev/initctl +fi + +# /config is relabeled earlier in boot (xenclient-config-access). +restore_firstboot -r /storage /var/log /var/cores /boot/system + +kill -USR1 1 + +# +# Execute swapon command again, in case we want to swap to +# a file on a now mounted filesystem. +# +swapon -a 2> /dev/null + +: exit 0 diff --git a/recipes-core/initscripts/initscripts-1.0/openxt-dom0/urandom b/recipes-core/initscripts/initscripts-1.0/openxt-dom0/urandom new file mode 100755 index 0000000000..d7c363cd43 --- /dev/null +++ b/recipes-core/initscripts/initscripts-1.0/openxt-dom0/urandom @@ -0,0 +1,61 @@ +#! /bin/sh +# +# Copyright (c) 2013 Citrix Systems, Inc. +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +# +# urandom This script saves the random seed between reboots. +# It is called from the boot, halt and reboot scripts. +# +# Version: @(#)urandom 1.33 22-Jun-1998 miquels@cistron.nl +# + +test -c /dev/urandom || exit 0 +. /etc/default/rcS + +SEED_FILE=/config/random-seed +POOL_SIZE=`cat /proc/sys/kernel/random/poolsize` || POOL_SIZE=4096 + +case "$1" in + start|"") + test "$VERBOSE" != no && echo "Initializing random number generator..." + # Carry a random seed from start-up to start-up. + # Load and then save the whole entropy pool. + if [ -f $SEED_FILE ]; then + cat $SEED_FILE > /dev/urandom + else + touch $SEED_FILE + fi + chmod 600 $SEED_FILE + dd if=/dev/urandom of=$SEED_FILE count=1 bs=$POOL_SIZE + ;; + stop) + # Carry a random seed from shut-down to start-up; + # see documentation in linux/drivers/char/random.c + test "$VERBOSE" != no && echo "Saving random seed..." + echo "Saving random seed..." + touch $SEED_FILE + chmod 600 $SEED_FILE + dd if=/dev/urandom of=$SEED_FILE count=1 bs=$POOL_SIZE + ;; + *) + echo "Usage: urandom {start|stop}" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/recipes-core/initscripts/initscripts-1.0/openxt-dom0/volatiles b/recipes-core/initscripts/initscripts-1.0/openxt-dom0/volatiles new file mode 100644 index 0000000000..8c726075b8 --- /dev/null +++ b/recipes-core/initscripts/initscripts-1.0/openxt-dom0/volatiles @@ -0,0 +1,37 @@ +# This configuration file lists filesystem objects that should get verified +# during startup and be created if missing. +# +# Every line must either be a comment starting with # +# or a definition of format: +# +# where the items are separated by whitespace ! +# +# : d|f|l : (d)irectory|(f)ile|(l)ink +# +# A linking example: +# l root root 0777 /var/test /tmp/testfile +# f root root 0644 /var/test none +# +# Understanding links: +# When populate-volatile is to verify/create a directory or file, it will first +# check it's existence. If a link is found to exist in the place of the target, +# the path of the target is replaced with the target the link points to. +# Thus, if a link is in the place to be verified, the object will be created +# in the place the link points to instead. +# This explains the order of "link before object" as in the example above, where +# a link will be created at /var/test pointing to /tmp/testfile and due to this +# link the file defined as /var/test will actually be created as /tmp/testfile. +d root root 1777 /run/lock none +l root root 1777 /var/lock /run/lock +d root root 0755 /var/lock/subsys none +f root root 0644 /var/log/lastlog none +f root root 0664 /var/run/utmp none +d root root 0755 /var/volatile/etc none +l root root 0777 /etc/asound.conf /var/volatile/etc/asound.conf +f root root 0644 /etc/asound.conf none +f root root 0644 /var/volatile/etc/resolv.conf none +f root root 0644 /var/volatile/etc/ifstate none +d root root 0755 /var/volatile/log none +f root root 0644 /var/volatile/log/wtmp none +f root root 0644 /var/run/hosts none + diff --git a/recipes-core/initscripts/initscripts-1.0/openxt-ndvm/finish.sh b/recipes-core/initscripts/initscripts-1.0/openxt-ndvm/finish.sh new file mode 100644 index 0000000000..6dd3ce332a --- /dev/null +++ b/recipes-core/initscripts/initscripts-1.0/openxt-ndvm/finish.sh @@ -0,0 +1,23 @@ +#!/bin/sh +# +# Copyright (c) 2013 Citrix Systems, Inc. +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +# Only used if boot-sentinel is set in the VM configuration +xenstore-write booted 1 + +exit 0 diff --git a/recipes-core/initscripts/initscripts-1.0/openxt-ndvm/volatiles b/recipes-core/initscripts/initscripts-1.0/openxt-ndvm/volatiles new file mode 100644 index 0000000000..ba00080f89 --- /dev/null +++ b/recipes-core/initscripts/initscripts-1.0/openxt-ndvm/volatiles @@ -0,0 +1,37 @@ +# This configuration file lists filesystem objects that should get verified +# during startup and be created if missing. +# +# Entries have the following format: +# +# where the items are separated by whitespace ! +# +# The # character introduces a comment lasting until end of line. +# Blank lines are ignored. +# +# : d|f|l : (d)irectory|(f)ile|(l)ink +# +# A linking example: +# l root root 0777 /var/test /tmp/testfile +# f root root 0644 /var/test none +# +# Understanding links: +# When populate-volatile is to verify/create a directory or file, it will first +# check it's existence. If a link is found to exist in the place of the target, +# the path of the target is replaced with the target the link points to. +# Thus, if a link is in the place to be verified, the object will be created +# in the place the link points to instead. +# This explains the order of "link before object" as in the example above, where +# a link will be created at /var/test pointing to /tmp/testfile and due to this +# link the file defined as /var/test will actually be created as /tmp/testfile. +d root root 1777 /run/lock none +l root root 1777 /var/lock /run/lock +d root root 0755 /var/volatile/log none +d root root 1777 /var/volatile/tmp none +d root root 0755 /var/volatile/etc none +l root root 0644 /etc/resolv.conf /var/run/NetworkManager/resolv.conf +f root root 0644 /var/volatile/etc/ifstate none +l root root 0755 /var/run /run +l root root 1777 /var/tmp /var/volatile/tmp +d root root 0755 /var/lock/subsys none +f root root 0664 /var/log/wtmp none +f root root 0664 /var/run/utmp none diff --git a/recipes-core/initscripts/initscripts-1.0/openxt-uivm/mountall.sh b/recipes-core/initscripts/initscripts-1.0/openxt-uivm/mountall.sh new file mode 100755 index 0000000000..1eef5a4ed1 --- /dev/null +++ b/recipes-core/initscripts/initscripts-1.0/openxt-uivm/mountall.sh @@ -0,0 +1,69 @@ +# +# Copyright (c) 2013 Citrix Systems, Inc. +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +# +# mountall.sh Mount all filesystems. +# +# Version: @(#)mountall.sh 2.83-2 01-Nov-2001 miquels@cistron.nl +# +. /etc/default/rcS + +[ -x /usr/bin/udevadm ] && /usr/bin/udevadm settle + +if test -f /etc/default/mountall; then + . /etc/default/mountall +fi + +mkdir -p /dev/pts /dev/shm + +# +# Mount local filesystems in /etc/fstab. For some reason, people +# might want to mount "proc" several times, and mount -v complains +# about this. So we mount "proc" filesystems without -v. +# +test "$VERBOSE" != no && echo "Mounting local filesystems..." +mount -a $MOUNTALL 2>&1 | logger -s -p user.err + +# +# Check if there's a /dev/xvda3. If so, mount it to /root/.gconf +# +if test -e /dev/xvda3 +then + umount /root/.gconf + mount -t ext3 /dev/xvda3 /root/.gconf + mount --bind /root/.gconf /root/.gnome2 +fi + +# +# We might have mounted something over /dev, see if /dev/initctl is there. +# +if test ! -p /dev/initctl +then + rm -f /dev/initctl + mknod -m 600 /dev/initctl p +fi +kill -USR1 1 + +# +# Execute swapon command again, in case we want to swap to +# a file on a now mounted filesystem. +# +swapon -a 2> /dev/null + +: exit 0 + diff --git a/recipes-core/initscripts/initscripts-1.0/openxt-uivm/single b/recipes-core/initscripts/initscripts-1.0/openxt-uivm/single new file mode 100755 index 0000000000..2d177ebb62 --- /dev/null +++ b/recipes-core/initscripts/initscripts-1.0/openxt-uivm/single @@ -0,0 +1,21 @@ +#! /bin/sh +# +# single executed by init(8) upon entering runlevel 1 (single). +# +# Version: @(#)single 1.20 26-Geb-2001 miquels@cistron.nl +# + +PATH="/sbin:/bin:/usr/sbin:/usr/bin" + +# Kill all processes. +echo "Sending all processes the TERM signal..." +killall5 -15 +sleep 5 +echo "Sending all processes the KILL signal..." +killall5 -9 + +# We start update here, since we just killed it. +test -x /sbin/update && update + +echo "Entering single-user mode..." +exec init -t1 S diff --git a/recipes-core/initscripts/initscripts-1.0/openxt-uivm/volatiles b/recipes-core/initscripts/initscripts-1.0/openxt-uivm/volatiles new file mode 100644 index 0000000000..0c3d0fae0f --- /dev/null +++ b/recipes-core/initscripts/initscripts-1.0/openxt-uivm/volatiles @@ -0,0 +1,37 @@ +# This configuration file lists filesystem objects that should get verified +# during startup and be created if missing. +# +# Every line must either be a comment starting with # +# or a definition of format: +# +# where the items are separated by whitespace ! +# +# : d|f|l : (d)irectory|(f)ile|(l)ink +# +# A linking example: +# l root root 0777 /var/test /tmp/testfile +# f root root 0644 /var/test none +# +# Understanding links: +# When populate-volatile is to verify/create a directory or file, it will first +# check it's existence. If a link is found to exist in the place of the target, +# the path of the target is replaced with the target the link points to. +# Thus, if a link is in the place to be verified, the object will be created +# in the place the link points to instead. +# This explains the order of "link before object" as in the example above, where +# a link will be created at /var/test pointing to /tmp/testfile and due to this +# link the file defined as /var/test will actually be created as /tmp/testfile. +d root root 1777 /run/lock none +l root root 1777 /var/lock /run/lock +d root root 0755 /var/lock/subsys none +f root root 0644 /var/log/lastlog none +f root root 0664 /var/run/utmp none +d root root 0755 /var/volatile/etc none +d root root 0755 /var/volatile/etc/asound none +f root root 0644 /var/volatile/etc/resolv.conf none +f root root 0644 /var/volatile/etc/ifstate none +d root root 0755 /var/volatile/log none +f root root 0644 /var/volatile/log/wtmp none +f root root 0644 /var/run/hosts none +d root root 0755 /var/volatile/dbus-session-root none +l root root 0755 /root/.dbus /var/volatile/dbus-session-root diff --git a/recipes-graphics/xorg-xserver/xserver-xf86-config/openxt-uivm/xorg.conf b/recipes-graphics/xorg-xserver/xserver-xf86-config/openxt-uivm/xorg.conf new file mode 100644 index 0000000000..d01a2b46b9 --- /dev/null +++ b/recipes-graphics/xorg-xserver/xserver-xf86-config/openxt-uivm/xorg.conf @@ -0,0 +1,15 @@ +# Xorg configuration for UIVM. + +Section "ServerFlags" + Option "DontZap" "true" + Option "DontVTSwitch" "true" + Option "BlankTime" "0" + Option "StandbyTime" "0" + Option "SuspendTime" "0" + Option "OffTime" "0" +EndSection + +Section "Device" + Identifier "openxtfb" + Driver "openxtfb" +EndSection diff --git a/recipes-kernel/linux/files/openxt-kmeta/bsp/common-pc/common-pc-drivers-reduced.cfg b/recipes-kernel/linux/files/openxt-kmeta/bsp/common-pc/common-pc-drivers-reduced.cfg new file mode 100644 index 0000000000..863b1dc673 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/bsp/common-pc/common-pc-drivers-reduced.cfg @@ -0,0 +1,65 @@ +# +# Serial ATA and Parallel ATA drivers (libata) +# +CONFIG_ATA=y +CONFIG_SATA_AHCI=y + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_EVDEV=y + +# +# Input Device Drivers +# +CONFIG_INPUT_MOUSE=y + +CONFIG_MOUSE_PS2=m + +CONFIG_MOUSE_APPLETOUCH=m +CONFIG_MOUSE_BCM5974=m +CONFIG_MOUSE_SYNAPTICS_I2C=m +CONFIG_INPUT_TABLET=y + +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ATMEL_MXT=m +CONFIG_TOUCHSCREEN_WACOM_W8001=m +CONFIG_TOUCHSCREEN_WACOM_I2C=m +CONFIG_TOUCHSCREEN_USB_COMPOSITE=m + +CONFIG_INPUT_MISC=y +CONFIG_INPUT_UINPUT=m + +# +# Hardware I/O ports +# +CONFIG_RTC_CLASS=y + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_I801=y + +# +# USB HID support +# +CONFIG_USB_HID=m +CONFIG_HID_PID=y +CONFIG_USB_HIDDEV=y + +# +# I2C HID support +# +CONFIG_I2C_HID=m + +# +# NVME Support +# +CONFIG_BLK_DEV_NVME=y diff --git a/recipes-kernel/linux/files/openxt-kmeta/bsp/common-pc/common-pc-eth-extended.cfg b/recipes-kernel/linux/files/openxt-kmeta/bsp/common-pc/common-pc-eth-extended.cfg new file mode 100644 index 0000000000..0f0efe6725 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/bsp/common-pc/common-pc-eth-extended.cfg @@ -0,0 +1,9 @@ +CONFIG_BNX2=m +CONFIG_CAVIUM_PTP=m +CONFIG_IGB=m +CONFIG_IGBVF=m +CONFIG_IXGB=m +CONFIG_IXGBE=m +CONFIG_IXGBEVF=m +CONFIG_I40E=m +CONFIG_I40EVF=m diff --git a/recipes-kernel/linux/files/openxt-kmeta/bsp/common-pc/common-pc-eth-extended.scc b/recipes-kernel/linux/files/openxt-kmeta/bsp/common-pc/common-pc-eth-extended.scc new file mode 100644 index 0000000000..01ede57bc0 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/bsp/common-pc/common-pc-eth-extended.scc @@ -0,0 +1,2 @@ +kconf hardware bsp/common-pc/common-pc-eth.cfg +kconf hardware common-pc-eth-extended.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/bsp/common-pc/common-pc-hid.cfg b/recipes-kernel/linux/files/openxt-kmeta/bsp/common-pc/common-pc-hid.cfg new file mode 100644 index 0000000000..6f2e00ed7b --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/bsp/common-pc/common-pc-hid.cfg @@ -0,0 +1,40 @@ +# +# HID support +# +CONFIG_HID=m +CONFIG_HIDRAW=y + +# +# Special HID drivers +# +CONFIG_HID_A4TECH=m +CONFIG_HID_APPLE=m +CONFIG_HID_BELKIN=m +CONFIG_HID_CHERRY=m +CONFIG_HID_CHICONY=m +CONFIG_HID_CYPRESS=m +CONFIG_HID_DRAGONRISE=m +CONFIG_HID_EZKEY=m +CONFIG_HID_KYE=m +CONFIG_HID_GYRATION=m +CONFIG_HID_ITE=m +CONFIG_HID_TWINHAN=m +CONFIG_HID_KENSINGTON=m +CONFIG_HID_LOGITECH=m +CONFIG_HID_LOGITECH_DJ=m +CONFIG_HID_MICROSOFT=m +CONFIG_HID_MONTEREY=m +CONFIG_HID_MULTITOUCH=m +CONFIG_HID_NTRIG=m +CONFIG_HID_PANTHERLORD=m +CONFIG_HID_PETALYNX=m +CONFIG_HID_SAMSUNG=m +CONFIG_HID_SONY=m +CONFIG_HID_SUNPLUS=m +CONFIG_HID_GREENASIA=m +CONFIG_HID_SMARTJOYPLUS=m +CONFIG_HID_TOPSEED=m +CONFIG_HID_THRUSTMASTER=m +CONFIG_HID_ZEROPLUS=m +CONFIG_HID_ALPS=m +CONFIG_HID_WACOM=m diff --git a/recipes-kernel/linux/files/openxt-kmeta/bsp/common-pc/common-pc-hid.scc b/recipes-kernel/linux/files/openxt-kmeta/bsp/common-pc/common-pc-hid.scc new file mode 100644 index 0000000000..4c110a4954 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/bsp/common-pc/common-pc-hid.scc @@ -0,0 +1 @@ +kconf hardware common-pc-hid.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/bsp/common-pc/common-pc-wifi-extended.cfg b/recipes-kernel/linux/files/openxt-kmeta/bsp/common-pc/common-pc-wifi-extended.cfg new file mode 100644 index 0000000000..5570f64915 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/bsp/common-pc/common-pc-wifi-extended.cfg @@ -0,0 +1,18 @@ +CONFIG_B43=m +CONFIG_IPW2100=m +CONFIG_IPW2100_MONITOR=y +CONFIG_IPW2100_DEBUG=y +CONFIG_IPW2200=m +CONFIG_IPW2200_MONITOR=y +CONFIG_IPW2200_PROMISCUOUS=y +CONFIG_IPW2200_QOS=y +CONFIG_IPW2200_DEBUG=y +CONFIG_LIBIPW=m +CONFIG_LIBIPW_DEBUG=y +CONFIG_IWL4965=m +CONFIG_IWL3945=m +CONFIG_IWLWIFI=m +CONFIG_IWLDVM=m +CONFIG_IWLMVM=m +CONFIG_RTL8723AE=m +CONFIG_RTLWIFI=m diff --git a/recipes-kernel/linux/files/openxt-kmeta/bsp/common-pc/common-pc-wifi-extended.scc b/recipes-kernel/linux/files/openxt-kmeta/bsp/common-pc/common-pc-wifi-extended.scc new file mode 100644 index 0000000000..a73fa0bdc0 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/bsp/common-pc/common-pc-wifi-extended.scc @@ -0,0 +1,2 @@ +kconf hardware bsp/common-pc/common-pc-wifi.cfg +kconf hardware common-pc-wifi-extended.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/bsp/common-xen-vm/common-xen-vm.cfg b/recipes-kernel/linux/files/openxt-kmeta/bsp/common-xen-vm/common-xen-vm.cfg new file mode 100644 index 0000000000..283de352cb --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/bsp/common-xen-vm/common-xen-vm.cfg @@ -0,0 +1,11 @@ +# +# Power management and ACPI options +# +# CONFIG_SUSPEND is not set +# CONFIG_SCHED_MC is not set + +# +# Device drivers +# +# CONFIG_PPS is not set +# CONFIG_PTP_1588_CLOCK is not set diff --git a/recipes-kernel/linux/files/openxt-kmeta/bsp/gpu/nouveau.cfg b/recipes-kernel/linux/files/openxt-kmeta/bsp/gpu/nouveau.cfg new file mode 100644 index 0000000000..9375fdfc7a --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/bsp/gpu/nouveau.cfg @@ -0,0 +1 @@ +CONFIG_DRM_NOUVEAU=m diff --git a/recipes-kernel/linux/files/openxt-kmeta/bsp/gpu/nouveau.scc b/recipes-kernel/linux/files/openxt-kmeta/bsp/gpu/nouveau.scc new file mode 100644 index 0000000000..64e2e11626 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/bsp/gpu/nouveau.scc @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: MIT +define KFEATURE_DESCRIPTION "Enable DRM support for Nouveau drivers" +define KFEATURE_COMPATIBILITY board + +kconf hardware nouveau.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/bsp/gpu/radeon.cfg b/recipes-kernel/linux/files/openxt-kmeta/bsp/gpu/radeon.cfg new file mode 100644 index 0000000000..bf442e24d9 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/bsp/gpu/radeon.cfg @@ -0,0 +1,2 @@ +CONFIG_DRM_RADEON=m +CONFIG_FB_RADEON=m diff --git a/recipes-kernel/linux/files/openxt-kmeta/bsp/gpu/radeon.scc b/recipes-kernel/linux/files/openxt-kmeta/bsp/gpu/radeon.scc new file mode 100644 index 0000000000..9c810dd861 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/bsp/gpu/radeon.scc @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: MIT +define KFEATURE_DESCRIPTION "Enable DRM support for Radeon drivers" +define KFEATURE_COMPATIBILITY board + +kconf hardware radeon.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/bsp/intel-x86/intel-x86-reduced.cfg b/recipes-kernel/linux/files/openxt-kmeta/bsp/intel-x86/intel-x86-reduced.cfg new file mode 100644 index 0000000000..ea57869207 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/bsp/intel-x86/intel-x86-reduced.cfg @@ -0,0 +1,165 @@ +# SPDX-License-Identifier: MIT +#......................................................................... +# WARNING +# +# This file is a kernel configuration fragment, and not a full kernel +# configuration file. The final kernel configuration is made up of +# an assembly of processed fragments, each of which is designed to +# capture a specific part of the final configuration (e.g. platform +# configuration, feature configuration, and board specific hardware +# configuration). For more information on kernel configuration, please +# consult the product documentation. +# +#......................................................................... + +# +# Processor type and features +# +CONFIG_MCORE2=y +CONFIG_SMP=y + +#CONFIG_X86_EXTENDED_PLATFORM is not set +#CONFIG_X86_INTEL_MID is not set + +CONFIG_MEMORY_FAILURE=y +CONFIG_HWPOISON_INJECT=m + +CONFIG_X86_INTEL_LPSS=y + +# +# Binary Emulations +# +# CONFIG_IA32_EMULATION is not set + +# +# I2C options +# +CONFIG_I2C_DESIGNWARE_PLATFORM=y +CONFIG_I2C_DESIGNWARE_PCI=y + +# +# PC SMBus host controller drivers +# +CONFIG_I2C_I801=m +CONFIG_I2C_ISCH=m +CONFIG_I2C_ISMT=m + +# +# Power management and ACPI options +# +CONFIG_PM=y + +CONFIG_HIBERNATION=y + +# +# Multifunction device drivers +# +CONFIG_LPC_ICH=m + +# +# x86 CPU frequency scaling drivers +# +CONFIG_X86_PCC_CPUFREQ=m +CONFIG_X86_ACPI_CPUFREQ=m +CONFIG_CPU_FREQ_GOV_POWERSAVE=m + +# +# Bus options (PCI etc.) +# +CONFIG_PCI=y +CONFIG_PCI_MSI=y +# CONFIG_HOTPLUG_PCI is not set + +CONFIG_PCIEPORTBUS=y + +CONFIG_PCI_STUB=m +CONFIG_PCI_IOV=y +# CONFIG_HOTPLUG_PCI_PCIE is not set + +# +#SD/MMC +# +CONFIG_MMC=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PCI=y +CONFIG_MMC_SDHCI_ACPI=y +CONFIG_MMC_SDHCI_PLTFM=y + +# +# Serial ATA and Parallel ATA drivers +# +CONFIG_ATA=y +CONFIG_SATA_AHCI=y +CONFIG_SATA_AHCI_PLATFORM=y + +# +# SCSI Transports +# +CONFIG_SCSI_SPI_ATTRS=y +CONFIG_SCSI_SAS_ATA=y +CONFIG_SCSI_ISCI=y +CONFIG_SCSI_MPT2SAS=y + +# +# EEPROM support +# + +# +# Hardware Monitoring support +# +CONFIG_SENSORS_ACPI_POWER=m +CONFIG_SENSORS_CORETEMP=m + +# +# Input device support +# +CONFIG_INPUT_MISC=y + +# +# PC SMBus host controller drivers +# +CONFIG_I2C_CHARDEV=m + +# +# Real Time Clock +# +CONFIG_RTC_CLASS=y +CONFIG_RTC_INTF_DEV_UIE_EMUL=y + +# +# Firmware Drivers +# +CONFIG_DMI_SYSFS=y + +# +# Library routines +# +CONFIG_CRC_T10DIF=y + +# +# Digest +# +CONFIG_CRYPTO=y + +# +# Ciphers +# +CONFIG_CRYPTO_AES_NI_INTEL=m + +# +# HID +# +CONFIG_HID=m +CONFIG_I2C_HID=m +CONFIG_HID_SENSOR_HUB=m + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=m + +# NVMe support +CONFIG_BLK_DEV_NVME=y + +# Touchscreen and zforce +CONFIG_INPUT_TOUCHSCREEN=y diff --git a/recipes-kernel/linux/files/openxt-kmeta/bsp/laptop/laptop-dell.cfg b/recipes-kernel/linux/files/openxt-kmeta/bsp/laptop/laptop-dell.cfg new file mode 100644 index 0000000000..03538f1323 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/bsp/laptop/laptop-dell.cfg @@ -0,0 +1,10 @@ +CONFIG_ACPI_WMI=m + +CONFIG_DCDBAS=y +CONFIG_DELL_SMBIOS=m +CONFIG_DELL_LAPTOP=m +CONFIG_DELL_WMI=m +CONFIG_DELL_WMI_AIO=m +# CONFIG_DELL_WMI_LED is not set +CONFIG_DELL_SMO8800=m +CONFIG_DELL_RBTN=m diff --git a/recipes-kernel/linux/files/openxt-kmeta/bsp/laptop/laptop-dell.scc b/recipes-kernel/linux/files/openxt-kmeta/bsp/laptop/laptop-dell.scc new file mode 100644 index 0000000000..24f68cbf81 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/bsp/laptop/laptop-dell.scc @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: MIT +define KFEATURE_DESCRIPTION "Enable support for Dell laptop extra features" +define KFEATURE_COMPATIBILITY board + +include features/rfkill/rfkill.scc + +kconf hardware laptop-dell.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/bsp/laptop/laptop-hp.cfg b/recipes-kernel/linux/files/openxt-kmeta/bsp/laptop/laptop-hp.cfg new file mode 100644 index 0000000000..fd7ed7ab70 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/bsp/laptop/laptop-hp.cfg @@ -0,0 +1,4 @@ +CONFIG_HP_ACCEL=m +CONFIG_HP_WIRELESS=m +CONFIG_HP_WMI=m +# CONFIG_LG_LAPTOP is not set diff --git a/recipes-kernel/linux/files/openxt-kmeta/bsp/laptop/laptop-hp.scc b/recipes-kernel/linux/files/openxt-kmeta/bsp/laptop/laptop-hp.scc new file mode 100644 index 0000000000..21e0f01f05 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/bsp/laptop/laptop-hp.scc @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: MIT +define KFEATURE_DESCRIPTION "Enable support for HP laptop extra features" +define KFEATURE_COMPATIBILITY board + +kconf hardware laptop-hp.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/bsp/laptop/laptop-thinkpad.cfg b/recipes-kernel/linux/files/openxt-kmeta/bsp/laptop/laptop-thinkpad.cfg new file mode 100644 index 0000000000..b56a7701d5 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/bsp/laptop/laptop-thinkpad.cfg @@ -0,0 +1 @@ +CONFIG_THINKPAD_ACPI=m diff --git a/recipes-kernel/linux/files/openxt-kmeta/bsp/laptop/laptop-thinkpad.scc b/recipes-kernel/linux/files/openxt-kmeta/bsp/laptop/laptop-thinkpad.scc new file mode 100644 index 0000000000..103df7b0a7 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/bsp/laptop/laptop-thinkpad.scc @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: MIT +define KFEATURE_DESCRIPTION "Enable support for Thinkpad laptop extra features" +define KFEATURE_COMPATIBILITY board + +kconf hardware laptop-thinkpad.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/bsp/livecd/intel-x86-64-livecd-xen.scc b/recipes-kernel/linux/files/openxt-kmeta/bsp/livecd/intel-x86-64-livecd-xen.scc new file mode 100644 index 0000000000..9e3df93cdf --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/bsp/livecd/intel-x86-64-livecd-xen.scc @@ -0,0 +1,19 @@ +define KMACHINE intel-x86-64 +define KTYPE livecd-xen +define KARCH x86_64 + +include ktypes/livecd/livecd-xen.scc + +# +# Generic intel/x86_64 +# +## intel-x86.scc includes too much support. +kconf hardware bsp/intel-x86/intel-x86-reduced.cfg +kconf hardware bsp/intel-x86/intel-x86-acpi.cfg +kconf hardware bsp/xen/intel-x86-64-smp.cfg + +# +# Include common PC support +# +kconf hardware bsp/common-pc/common-pc-drivers-reduced.cfg +kconf hardware bsp/common-pc/common-pc-gfx.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/bsp/livecd/intel-x86-64-livecd.scc b/recipes-kernel/linux/files/openxt-kmeta/bsp/livecd/intel-x86-64-livecd.scc new file mode 100644 index 0000000000..4aee71754e --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/bsp/livecd/intel-x86-64-livecd.scc @@ -0,0 +1,19 @@ +define KMACHINE intel-x86-64 +define KTYPE livecd +define KARCH x86_64 + +include ktypes/livecd/livecd.scc + +# +# Generic intel/x86_64 +# +## intel-x86.scc includes too much support. +kconf hardware bsp/intel-x86/intel-x86-reduced.cfg +kconf hardware bsp/intel-x86/intel-x86-acpi.cfg +kconf hardware bsp/xen/intel-x86-64-smp.cfg + +# +# Include common PC support +# +kconf hardware bsp/common-pc/common-pc-drivers-reduced.cfg +kconf hardware bsp/common-pc/common-pc-gfx.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/bsp/xen/intel-x86-64-dom0.cfg b/recipes-kernel/linux/files/openxt-kmeta/bsp/xen/intel-x86-64-dom0.cfg new file mode 100644 index 0000000000..97b03b5448 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/bsp/xen/intel-x86-64-dom0.cfg @@ -0,0 +1,16 @@ +CONFIG_XEN_MCE_LOG=y + +# +# Networking support +# +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y + +# +# Device Drivers +# +# CONFIG_PCI_PRI is not set +# CONFIG_PCI_PASID is not set +# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set + +# CONFIG_ATA_SFF is not set diff --git a/recipes-kernel/linux/files/openxt-kmeta/bsp/xen/intel-x86-64-dom0.scc b/recipes-kernel/linux/files/openxt-kmeta/bsp/xen/intel-x86-64-dom0.scc new file mode 100644 index 0000000000..8a57e5a509 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/bsp/xen/intel-x86-64-dom0.scc @@ -0,0 +1,24 @@ +define KMACHINE intel-x86-64 +define KTYPE dom0 +define KARCH x86_64 + +include ktypes/xen/dom0.scc + +# +# Generic intel/x86_64 +# +## intel-x86.scc includes too much support. +kconf hardware bsp/intel-x86/intel-x86-reduced.cfg +kconf hardware bsp/intel-x86/intel-x86-acpi.cfg +kconf hardware bsp/xen/intel-x86-64-smp.cfg + +# +# Include common PC support +# +kconf hardware bsp/common-pc/common-pc-drivers-reduced.cfg +kconf hardware bsp/common-pc/common-pc-gfx.cfg + +# +# Overrides for dom0, keep last. +# +kconf hardware bsp/xen/intel-x86-64-dom0.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/bsp/xen/intel-x86-64-ndvm.cfg b/recipes-kernel/linux/files/openxt-kmeta/bsp/xen/intel-x86-64-ndvm.cfg new file mode 100644 index 0000000000..282d24c843 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/bsp/xen/intel-x86-64-ndvm.cfg @@ -0,0 +1,10 @@ +# +# Networking support +# +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y + +# +# General architecture-dependent options +# +# CONFIG_BLK_DEV_INITRD is not set diff --git a/recipes-kernel/linux/files/openxt-kmeta/bsp/xen/intel-x86-64-ndvm.scc b/recipes-kernel/linux/files/openxt-kmeta/bsp/xen/intel-x86-64-ndvm.scc new file mode 100644 index 0000000000..0399ec43f2 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/bsp/xen/intel-x86-64-ndvm.scc @@ -0,0 +1,15 @@ +define KMACHINE intel-x86-64 +define KTYPE ndvm +define KARCH x86_64 + +include ktypes/xen/ndvm.scc + +# +# CPU configuration +# +kconf hardware bsp/xen/intel-x86-64-smp.cfg +kconf hardware bsp/common-xen-vm/common-xen-vm.cfg + +kconf hardware intel-x86-64-vm.cfg + +kconf hardware intel-x86-64-ndvm.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/bsp/xen/intel-x86-64-smp.cfg b/recipes-kernel/linux/files/openxt-kmeta/bsp/xen/intel-x86-64-smp.cfg new file mode 100644 index 0000000000..bd7ff445ab --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/bsp/xen/intel-x86-64-smp.cfg @@ -0,0 +1,10 @@ +# +# Processor type and features +# +CONFIG_SMP=y +CONFIG_NR_CPUS=8 + +# +# Binary Emulations +# +# CONFIG_IA32_EMULATION is not set diff --git a/recipes-kernel/linux/files/openxt-kmeta/bsp/xen/intel-x86-64-stubdom.cfg b/recipes-kernel/linux/files/openxt-kmeta/bsp/xen/intel-x86-64-stubdom.cfg new file mode 100644 index 0000000000..e69de29bb2 diff --git a/recipes-kernel/linux/files/openxt-kmeta/bsp/xen/intel-x86-64-stubdom.scc b/recipes-kernel/linux/files/openxt-kmeta/bsp/xen/intel-x86-64-stubdom.scc new file mode 100644 index 0000000000..9f15c4e918 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/bsp/xen/intel-x86-64-stubdom.scc @@ -0,0 +1,15 @@ +define KMACHINE intel-x86-64 +define KTYPE stubdom +define KARCH x86_64 + +include ktypes/xen/stubdom.scc + +# +# CPU configuration +# +kconf hardware bsp/xen/intel-x86-64-smp.cfg +kconf hardware bsp/common-xen-vm/common-xen-vm.cfg + +kconf hardware intel-x86-64-vm.cfg + +kconf hardware intel-x86-64-stubdom.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/bsp/xen/intel-x86-64-uivm.cfg b/recipes-kernel/linux/files/openxt-kmeta/bsp/xen/intel-x86-64-uivm.cfg new file mode 100644 index 0000000000..76ad70bd3b --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/bsp/xen/intel-x86-64-uivm.cfg @@ -0,0 +1,9 @@ +# +# General architecture-dependent options +# +# CONFIG_BLK_DEV_INITRD is not set + +# +# Device drivers +# +# CONFIG_ATA_SFF is not set diff --git a/recipes-kernel/linux/files/openxt-kmeta/bsp/xen/intel-x86-64-uivm.scc b/recipes-kernel/linux/files/openxt-kmeta/bsp/xen/intel-x86-64-uivm.scc new file mode 100644 index 0000000000..dac8cd7a30 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/bsp/xen/intel-x86-64-uivm.scc @@ -0,0 +1,15 @@ +define KMACHINE intel-x86-64 +define KTYPE uivm +define KARCH x86_64 + +include ktypes/xen/uivm.scc + +# +# CPU configuration +# +kconf hardware bsp/xen/intel-x86-64-smp.cfg +kconf hardware bsp/common-xen-vm/common-xen-vm.cfg + +kconf hardware intel-x86-64-vm.cfg + +kconf hardware intel-x86-64-uivm.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/bsp/xen/intel-x86-64-vm.cfg b/recipes-kernel/linux/files/openxt-kmeta/bsp/xen/intel-x86-64-vm.cfg new file mode 100644 index 0000000000..be4d8232a4 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/bsp/xen/intel-x86-64-vm.cfg @@ -0,0 +1,10 @@ +# +# Processor type and features +# +# CONFIG_X86_EXTENDED_PLATFORM is not set +# CONFIG_X86_MCE is not set + +# +# Device drivers +# +# CONFIG_X86_PLATFORM_DEVICES is not set diff --git a/recipes-kernel/linux/files/openxt-kmeta/cfg/initrd-gz.cfg b/recipes-kernel/linux/files/openxt-kmeta/cfg/initrd-gz.cfg new file mode 100644 index 0000000000..397ec34147 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/cfg/initrd-gz.cfg @@ -0,0 +1,6 @@ +CONFIG_BLK_DEV_INITRD=y +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set diff --git a/recipes-kernel/linux/files/openxt-kmeta/cfg/initrd-gz.scc b/recipes-kernel/linux/files/openxt-kmeta/cfg/initrd-gz.scc new file mode 100644 index 0000000000..7a4e7d2156 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/cfg/initrd-gz.scc @@ -0,0 +1,4 @@ +define KFEATURE_DESCRIPTION "Enable initrd gzip compression scheme" +define KFEATURE_COMPATIBILITY all + +kconf non-hardware initrd-gz.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/cfg/livecd-fs.cfg b/recipes-kernel/linux/files/openxt-kmeta/cfg/livecd-fs.cfg new file mode 100644 index 0000000000..9abbf064b1 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/cfg/livecd-fs.cfg @@ -0,0 +1,3 @@ +CONFIG_ISO9660_FS=m +CONFIG_ZISOFS=y +CONFIG_JOLIET=y diff --git a/recipes-kernel/linux/files/openxt-kmeta/cfg/livecd-fs.scc b/recipes-kernel/linux/files/openxt-kmeta/cfg/livecd-fs.scc new file mode 100644 index 0000000000..9d6c5d2fec --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/cfg/livecd-fs.scc @@ -0,0 +1,4 @@ +define KFEATURE_DESCRIPTION "Enable live CD file-system support" +define KFEATURE_COMPATIBILITY all + +kconf non-hardware livecd-fs.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/cfg/luks-lvm.cfg b/recipes-kernel/linux/files/openxt-kmeta/cfg/luks-lvm.cfg new file mode 100644 index 0000000000..97be880cc3 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/cfg/luks-lvm.cfg @@ -0,0 +1,9 @@ +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=y +CONFIG_DM_UEVENT=y + +CONFIG_CRYPTO_AES=y +CONFIG_CRYPTO_SHA256=y + +CONFIG_CRYPTO_XTS=m diff --git a/recipes-kernel/linux/files/openxt-kmeta/cfg/luks-lvm.scc b/recipes-kernel/linux/files/openxt-kmeta/cfg/luks-lvm.scc new file mode 100644 index 0000000000..b0c68a961f --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/cfg/luks-lvm.scc @@ -0,0 +1,4 @@ +define KFEATURE_DESCRIPTION "Enable multi-device driver and crypto" +define KFEATURE_COMPATIBILITY all + +kconf non-hardware luks-lvm.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/cfg/openxt-common.cfg b/recipes-kernel/linux/files/openxt-kmeta/cfg/openxt-common.cfg new file mode 100644 index 0000000000..733fc1181f --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/cfg/openxt-common.cfg @@ -0,0 +1,36 @@ +# +# General architecture-dependent options +# +# CONFIG_KPROBES is not set + +# +# Networking +# +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_PACKET=y +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_IPV6 is not set + +# +# File systems +# +# CONFIG_MISC_FILESYSTEMS is not set +# CONFIG_NETWORK_FILESYSTEMS is not set + +# +# Cryptographic API +# +# CONFIG_CRYPTO_HW is not set + +# +# Kernel hacking +# +# CONFIG_UPROBE_EVENTS is not set +CONFIG_PRINTK_TIME=y +CONFIG_DYNAMIC_DEBUG=y +# CONFIG_RUNTIME_TESTING_MENU is not set diff --git a/recipes-kernel/linux/files/openxt-kmeta/cfg/openxt-common.scc b/recipes-kernel/linux/files/openxt-kmeta/cfg/openxt-common.scc new file mode 100644 index 0000000000..97e2c8fd6c --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/cfg/openxt-common.scc @@ -0,0 +1,21 @@ +define KFEATURE_DESCRIPTION "Standard OpenXT service VMs configuration" +define KFEATURE_COMPATIBILITY all + +# +# Force module signing +# +include features/module-signing/signing.scc +include features/module-signing/force-signing.scc + +# +# Security kernel configurations. +# +include features/security/security.scc + +# +# File-systems +# +include cfg/fs/ext3.scc +include cfg/fs/ext4.scc + +kconf non-hardware openxt-common.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/features/netfilter/netfilter-physdev.cfg b/recipes-kernel/linux/files/openxt-kmeta/features/netfilter/netfilter-physdev.cfg new file mode 100644 index 0000000000..756371f03a --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/features/netfilter/netfilter-physdev.cfg @@ -0,0 +1 @@ +CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m diff --git a/recipes-kernel/linux/files/openxt-kmeta/features/netfilter/netfilter-physdev.scc b/recipes-kernel/linux/files/openxt-kmeta/features/netfilter/netfilter-physdev.scc new file mode 100644 index 0000000000..68d98ae9bb --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/features/netfilter/netfilter-physdev.scc @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: MIT +define KFEATURE_DESCRIPTION "Enable netfilter physdev packet matching module." +define KFEATURE_COMPATIBILITY arch + +kconf non-hardware netfilter-physdev.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-balloon.cfg b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-balloon.cfg new file mode 100644 index 0000000000..31dee6891b --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-balloon.cfg @@ -0,0 +1,2 @@ +CONFIG_XEN_BALLOON=y +CONFIG_XEN_SCRUB_PAGES_DEFAULT=y diff --git a/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-balloon.scc b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-balloon.scc new file mode 100644 index 0000000000..601b78cb4b --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-balloon.scc @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: MIT +define KFEATURE_DESCRIPTION "Enable Xen memory balloon module" +define KFEATURE_COMPATIBILITY arch + +kconf non-hardware xen-balloon.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-blk-be.cfg b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-blk-be.cfg new file mode 100644 index 0000000000..7ce3de2e59 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-blk-be.cfg @@ -0,0 +1,2 @@ +CONFIG_XEN_BACKEND=y +CONFIG_XEN_BLKDEV_BACKEND=y diff --git a/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-blk-be.scc b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-blk-be.scc new file mode 100644 index 0000000000..59cb0a0983 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-blk-be.scc @@ -0,0 +1,4 @@ +define KFEATURE_DESCRIPTION "Enable Xen block device backend driver" +define KFEATURE_COMPATIBILITY arch + +kconf non-hardware xen-blk-be.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-blk-fe.cfg b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-blk-fe.cfg new file mode 100644 index 0000000000..2473142aaa --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-blk-fe.cfg @@ -0,0 +1 @@ +CONFIG_XEN_BLKDEV_FRONTEND=y diff --git a/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-blk-fe.scc b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-blk-fe.scc new file mode 100644 index 0000000000..ddc924ba6f --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-blk-fe.scc @@ -0,0 +1,4 @@ +define KFEATURE_DESCRIPTION "Enable Xen paravirtualized block device driver." +define KFEATURE_COMPATIBILITY arch + +kconf non-hardware xen-blk-fe.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-debugfs.cfg b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-debugfs.cfg new file mode 100644 index 0000000000..f250e987f2 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-debugfs.cfg @@ -0,0 +1 @@ +CONFIG_XEN_DEBUG_FS=y diff --git a/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-debugfs.scc b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-debugfs.scc new file mode 100644 index 0000000000..5be56e4d08 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-debugfs.scc @@ -0,0 +1,4 @@ +define KFEATURE_DESCRIPTION "Enable Xen debug file-system" +define KFEATURE_COMPATIBILITY arch + +kconf non-hardware xen-debugfs.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-dom0.cfg b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-dom0.cfg new file mode 100644 index 0000000000..e588eb647c --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-dom0.cfg @@ -0,0 +1,3 @@ +CONFIG_HYPERVISOR_GUEST=y +CONFIG_PARAVIRT=y +CONFIG_XEN=y diff --git a/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-dom0.scc b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-dom0.scc new file mode 100644 index 0000000000..9116808058 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-dom0.scc @@ -0,0 +1,4 @@ +define KFEATURE_DESCRIPTION "Enable Xen dom0 kernel support" +define KFEATURE_COMPATIBILITY arch + +kconf non-hardware xen-dom0.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-net-be.cfg b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-net-be.cfg new file mode 100644 index 0000000000..86c293f54c --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-net-be.cfg @@ -0,0 +1,2 @@ +CONFIG_XEN_BACKEND=y +CONFIG_XEN_NETDEV_BACKEND=m diff --git a/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-net-be.scc b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-net-be.scc new file mode 100644 index 0000000000..f92e122879 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-net-be.scc @@ -0,0 +1,4 @@ +define KFEATURE_DESCRIPTION "Enable Xen backend network device" +define KFEATURE_COMPATIBILITY arch + +kconf non-hardware xen-net-be.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-net-fe.cfg b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-net-fe.cfg new file mode 100644 index 0000000000..726a687a65 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-net-fe.cfg @@ -0,0 +1,2 @@ +CONFIG_NETDEVICES=y +CONFIG_XEN_NETDEV_FRONTEND=m diff --git a/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-net-fe.scc b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-net-fe.scc new file mode 100644 index 0000000000..e73683e153 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-net-fe.scc @@ -0,0 +1,4 @@ +define KFEATURE_DESCRIPTION "Enable Xen network device frontend driver" +define KFEATURE_COMPATIBILITY arch + +kconf non-hardware xen-net-fe.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-pci-be.cfg b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-pci-be.cfg new file mode 100644 index 0000000000..fb4bac7977 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-pci-be.cfg @@ -0,0 +1,3 @@ +CONFIG_XEN_BACKEND=y +CONFIG_XEN_PCIDEV_BACKEND=m +CONFIG_PCI_STUB=y diff --git a/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-pci-be.scc b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-pci-be.scc new file mode 100644 index 0000000000..4dc6a0324f --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-pci-be.scc @@ -0,0 +1,4 @@ +define KFEATURE_DESCRIPTION "Enable Xen PCI-device backend driver" +define KFEATURE_COMPATIBILITY arch + +kconf non-hardware xen-pci-be.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-pci-fe.cfg b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-pci-fe.cfg new file mode 100644 index 0000000000..66a6c16e0a --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-pci-fe.cfg @@ -0,0 +1,2 @@ +CONFIG_PCI=y +CONFIG_XEN_PCIDEV_FRONTEND=m diff --git a/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-pci-fe.scc b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-pci-fe.scc new file mode 100644 index 0000000000..bf56bf2a71 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-pci-fe.scc @@ -0,0 +1,5 @@ +define KFEATURE_DESCRIPTION "Enable Xen paravirtualized PCI driver." +define KFEATURE_COMPATIBILITY arch + +kconf non-hardware xen-pci-fe.cfg + diff --git a/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-pv.cfg b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-pv.cfg new file mode 100644 index 0000000000..59c537751c --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-pv.cfg @@ -0,0 +1,4 @@ +CONFIG_HYPERVISOR_GUEST=y +CONFIG_PARAVIRT=y +CONFIG_XEN=y +CONFIG_XEN_PV=y diff --git a/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-pv.scc b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-pv.scc new file mode 100644 index 0000000000..d3847454e8 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-pv.scc @@ -0,0 +1,4 @@ +define KFEATURE_DESCRIPTION "Enable Xen PV guest kernel support" +define KFEATURE_COMPATIBILITY arch + +kconf non-hardware xen-pv.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-pvh.cfg b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-pvh.cfg new file mode 100644 index 0000000000..3a94f365c8 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-pvh.cfg @@ -0,0 +1,15 @@ +# +# Processor type and features +# +CONFIG_HYPERVISOR_GUEST=y +CONFIG_PARAVIRT=y +CONFIG_XEN=y +CONFIG_XEN_PV=y +CONFIG_PARAVIRT_TIME_ACCOUNTING=y +CONFIG_XEN_PVH=y +# CONFIG_SCHED_MC is not set + +# +# Device drivers +# +CONFIG_PCI=y diff --git a/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-pvh.scc b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-pvh.scc new file mode 100644 index 0000000000..347f57c139 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-pvh.scc @@ -0,0 +1,4 @@ +define KFEATURE_DESCRIPTION "Enable Xen PVH guest kernel support" +define KFEATURE_COMPATIBILITY arch + +kconf non-hardware xen-pvh.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-pvhvm.cfg b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-pvhvm.cfg new file mode 100644 index 0000000000..cf1352cb84 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-pvhvm.cfg @@ -0,0 +1,5 @@ +CONFIG_PARAVIRT=y +CONFIG_HYPERVISOR_GUEST=y +CONFIG_XEN=y +# CONFIG_XEN_DOM0 is not set +CONFIG_PCI=y diff --git a/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-pvhvm.scc b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-pvhvm.scc new file mode 100644 index 0000000000..4b3c49f173 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-pvhvm.scc @@ -0,0 +1,4 @@ +define KFEATURE_DESCRIPTION "Enable Xen PV on HVM (Xen platform device) in guest support" +define KFEATURE_COMPATIBILITY arch + +kconf non-hardware xen-pvhvm.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-vfb-fe.cfg b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-vfb-fe.cfg new file mode 100644 index 0000000000..9a7fa19cd6 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-vfb-fe.cfg @@ -0,0 +1 @@ +CONFIG_XEN_FBDEV_FRONTEND=m diff --git a/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-vfb-fe.scc b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-vfb-fe.scc new file mode 100644 index 0000000000..5ca930c8f4 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-vfb-fe.scc @@ -0,0 +1,4 @@ +define KFEATURE_DESCRIPTION "Enable Xen virtual framebuffer frontend driver" +define KFEATURE_COMPATIBILITY arch + +kconf non-hardware xen-vfb-fe.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-vkbd-fe.cfg b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-vkbd-fe.cfg new file mode 100644 index 0000000000..6d78d799bd --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-vkbd-fe.cfg @@ -0,0 +1,2 @@ +CONFIG_INPUT_MISC=y +CONFIG_INPUT_XEN_KBDDEV_FRONTEND=m diff --git a/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-vkbd-fe.scc b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-vkbd-fe.scc new file mode 100644 index 0000000000..796da9d5c3 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/features/xen/xen-vkbd-fe.scc @@ -0,0 +1,4 @@ +define KFEATURE_DESCRIPTION "Enable Xen virtual keyboard frontend driver" +define KFEATURE_COMPATIBILITY arch + +kconf non-hardware xen-vkbd-fe.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/ktypes/livecd/livecd-xen.cfg b/recipes-kernel/linux/files/openxt-kmeta/ktypes/livecd/livecd-xen.cfg new file mode 100644 index 0000000000..7a6fcf605d --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/ktypes/livecd/livecd-xen.cfg @@ -0,0 +1,42 @@ +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y + +# +# General architecture-dependent options +# +# CONFIG_VIRTUALIZATION is not set + +# +# Security options +# +CONFIG_SECURITY=y + +# +# Networking support +# +# CONFIG_TIPC is not set +# CONFIG_ATM is not set + +# +# Device Drivers +# +# CONFIG_VIRTIO_MENU is not set + +CONFIG_BLK_DEV_LOOP=y + +# CONFIG_IOMMU_SUPPORT is not set + +# CONFIG_LEGACY_PTYS is not set + +# +# Processor type and features +# +# CONFIG_KVM_GUEST is not set diff --git a/recipes-kernel/linux/files/openxt-kmeta/ktypes/livecd/livecd-xen.scc b/recipes-kernel/linux/files/openxt-kmeta/ktypes/livecd/livecd-xen.scc new file mode 100644 index 0000000000..e667c8984f --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/ktypes/livecd/livecd-xen.scc @@ -0,0 +1,6 @@ +define KERNEL_VERSION 5.4 +branch v5.4 + +force kconf non-hardware livecd.cfg + +include ktypes/xen/dom0.scc diff --git a/recipes-kernel/linux/files/openxt-kmeta/ktypes/livecd/livecd.cfg b/recipes-kernel/linux/files/openxt-kmeta/ktypes/livecd/livecd.cfg new file mode 100644 index 0000000000..7a6fcf605d --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/ktypes/livecd/livecd.cfg @@ -0,0 +1,42 @@ +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y + +# +# General architecture-dependent options +# +# CONFIG_VIRTUALIZATION is not set + +# +# Security options +# +CONFIG_SECURITY=y + +# +# Networking support +# +# CONFIG_TIPC is not set +# CONFIG_ATM is not set + +# +# Device Drivers +# +# CONFIG_VIRTIO_MENU is not set + +CONFIG_BLK_DEV_LOOP=y + +# CONFIG_IOMMU_SUPPORT is not set + +# CONFIG_LEGACY_PTYS is not set + +# +# Processor type and features +# +# CONFIG_KVM_GUEST is not set diff --git a/recipes-kernel/linux/files/openxt-kmeta/ktypes/livecd/livecd.scc b/recipes-kernel/linux/files/openxt-kmeta/ktypes/livecd/livecd.scc new file mode 100644 index 0000000000..a80105c431 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/ktypes/livecd/livecd.scc @@ -0,0 +1,27 @@ +define KERNEL_VERSION 5.4 +branch v5.4 + +force kconf non-hardware livecd.cfg + +include features/lttng/lttng.scc + +include features/blktrace/blktrace.scc + +include features/utrace/utrace.scc + +include features/seccomp/seccomp.scc + +include features/ftrace/ftrace.scc + +# Initramfs gen_initramfs_list.sh hook +include features/initramfs/initramfs.scc + +include features/tmpfs/tmpfs-posix-acl.scc + +include features/edac/edac.scc + +# individual cfg block section +include cfg/fs/devtmpfs.scc +include cfg/fs/debugfs.scc + +include cfg/systemd.scc diff --git a/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/base.cfg b/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/base.cfg new file mode 100644 index 0000000000..985895a64f --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/base.cfg @@ -0,0 +1,44 @@ +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y + +# +# General architecture-dependent options +# +# CONFIG_VIRTUALIZATION is not set + +# +# Security options +# +CONFIG_SECURITY=y + +# +# Networking support +# +# CONFIG_TIPC is not set +# CONFIG_ATM is not set + +# +# Device Drivers +# +# CONFIG_VIRTIO_MENU is not set + +CONFIG_BLK_DEV_LOOP=y + +# CONFIG_IOMMU_SUPPORT is not set + +# CONFIG_LEGACY_PTYS is not set + +# CONFIG_XEN_BALLOON is not set + +# +# Processor type and features +# +# CONFIG_KVM_GUEST is not set diff --git a/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/base.scc b/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/base.scc new file mode 100644 index 0000000000..2761d32b5e --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/base.scc @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: MIT +define KERNEL_VERSION 5.4 +branch v5.4 + +force kconf non-hardware base.cfg + +include features/lttng/lttng.scc + +include features/blktrace/blktrace.scc + +include features/utrace/utrace.scc + +include features/seccomp/seccomp.scc + +include features/ftrace/ftrace.scc + +# Initramfs gen_initramfs_list.sh hook +include features/initramfs/initramfs.scc + +include features/tmpfs/tmpfs-posix-acl.scc + +include features/edac/edac.scc + +# individual cfg block section +include cfg/fs/devtmpfs.scc +include cfg/fs/debugfs.scc + +include cfg/systemd.scc diff --git a/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/dom0.cfg b/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/dom0.cfg new file mode 100644 index 0000000000..936c05e97a --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/dom0.cfg @@ -0,0 +1,16 @@ +# +# Processor type and features +# +# CONFIG_XEN_PVHVM is not set + +# +# Device drivers +# +# CONFIG_XEN_PCIDEV_FRONTEND is not set +# CONFIG_XEN_BLKDEV_FRONTEND is not set +# CONFIG_XEN_FBDEV_FRONTEND is not set + +# CONFIG_WIRELESS is not set +# CONFIG_ETHERNET is not set +# CONFIG_WLAN is not set +# CONFIG_BLK_DEV_MD is not set diff --git a/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/dom0.scc b/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/dom0.scc new file mode 100644 index 0000000000..650f064dfb --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/dom0.scc @@ -0,0 +1,13 @@ +include ktypes/xen/base.scc + +# Firmware loading support. +include features/firmware/firmware.scc + +# PCI support (PCI backend support). +include features/pci/pci.scc +include features/pci-iov/pci-iov.scc + +# Xen dom0 support. +include features/xen/xen-dom0.scc + +kconf non-hardware ktypes/xen/dom0.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/hvm.cfg b/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/hvm.cfg new file mode 100644 index 0000000000..9ba566f4a8 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/hvm.cfg @@ -0,0 +1,9 @@ +# +# Processor type and features +# +CONFIG_XEN_PVHVM=y + +# +# SPI support +# +# CONFIG_SPI is not set diff --git a/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/hvm.scc b/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/hvm.scc new file mode 100644 index 0000000000..c1792b0532 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/hvm.scc @@ -0,0 +1,13 @@ +include ktypes/xen/base.scc + +# Firmware loading support. +include features/firmware/firmware.scc + +# PCI support (PCI backend support). +include features/pci/pci.scc +include features/pci-iov/pci-iov.scc + +# Xen PV on HVM support. +include features/xen/xen-pvhvm.scc + +kconf non-hardware ktypes/xen/hvm.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/ndvm.cfg b/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/ndvm.cfg new file mode 100644 index 0000000000..921c5ce26a --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/ndvm.cfg @@ -0,0 +1,13 @@ +# +# Networking +# +CONFIG_BRIDGE=y + +# +# Device drivers +# +# CONFIG_CDROM is not set +# CONFIG_SCSI is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_HID is not set +# CONFIG_USB_SUPPORT is not set diff --git a/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/ndvm.scc b/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/ndvm.scc new file mode 100644 index 0000000000..1d629487dd --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/ndvm.scc @@ -0,0 +1,14 @@ +include ktypes/xen/hvm.scc + +# +# Xen PV on HVM support +# +include features/xen/xen-pvhvm.scc + +# +# Xen paravirtualized backends +# +include features/xen/xen-net-be.scc +include features/xen/xen-blk-fe.scc + +kconf non-hardware ndvm.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/pv.cfg b/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/pv.cfg new file mode 100644 index 0000000000..7de165c7cc --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/pv.cfg @@ -0,0 +1,38 @@ +# +# Processor type and features +# +# CONFIG_XEN_PVHVM is not set + +# +# Power management and ACPI options +# +# CONFIG_ACPI is not set + +# +# Device drivers +# +# CONFIG_XEN_BALLOON is not set +# CONFIG_XEN_PCIDEV_FRONTEND is not set +# CONFIG_XEN_FBDEV_FRONTEND is not set +# CONFIG_XEN_BLKDEV_FRONTEND is not set + +# CONFIG_WIRELESS is not set +# CONFIG_ETHERNET is not set +# CONFIG_WLAN is not set +# CONFIG_PPP is not set +# CONFIG_NET_CORE is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_DEVPORT is not set +# CONFIG_HWMON is not set +# CONFIG_SERIO is not set +# CONFIG_USB_SUPPORT is not set + +# +# Cryptographic API +# +# CONFIG_CRYPTO_HW is not set + +# +# SPI support +# +# CONFIG_SPI is not set diff --git a/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/pv.scc b/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/pv.scc new file mode 100644 index 0000000000..e46a1f3f06 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/pv.scc @@ -0,0 +1,6 @@ +include ktypes/xen/base.scc + +# Xen PV support. +include features/xen/xen-pv.scc + +kconf non-hardware ktypes/xen/pv.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/pvh.cfg b/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/pvh.cfg new file mode 100644 index 0000000000..4da8f5b9ff --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/pvh.cfg @@ -0,0 +1,27 @@ +# +# SPI support +# +# CONFIG_SPI is not set + +# +# Device drivers +# +# CONFIG_XEN_BALLOON is not set +# CONFIG_XEN_PCIDEV_FRONTEND is not set +# CONFIG_XEN_FBDEV_FRONTEND is not set +# CONFIG_XEN_BLKDEV_FRONTEND is not set + +# CONFIG_WIRELESS is not set +# CONFIG_ETHERNET is not set +# CONFIG_WLAN is not set +# CONFIG_PPP is not set +# CONFIG_NET_CORE is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_DEVPORT is not set +# CONFIG_HWMON is not set +# CONFIG_SERIO is not set +# CONFIG_USB_SUPPORT is not set + +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_HID is not set diff --git a/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/pvh.scc b/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/pvh.scc new file mode 100644 index 0000000000..827cf4036f --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/pvh.scc @@ -0,0 +1,6 @@ +include ktypes/xen/base.scc + +# Xen PVH support. +include features/xen/xen-pvh.scc + +kconf non-hardware ktypes/xen/pvh.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/stubdom.cfg b/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/stubdom.cfg new file mode 100644 index 0000000000..e4b07a193d --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/stubdom.cfg @@ -0,0 +1,16 @@ +# +# Device drivers +# +# CONFIG_INPUT is not set +# CONFIG_VT is not set + +# +# Network device support +# +CONFIG_NET_CORE=y +CONFIG_TUN=y + +# +# Networking options +# +CONFIG_BRIDGE=y diff --git a/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/stubdom.scc b/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/stubdom.scc new file mode 100644 index 0000000000..15b0f58cba --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/stubdom.scc @@ -0,0 +1,3 @@ +include ktypes/xen/pv.scc + +kconf non-hardware stubdom.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/uivm.cfg b/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/uivm.cfg new file mode 100644 index 0000000000..72b1e802ab --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/uivm.cfg @@ -0,0 +1,20 @@ +# +# Processor type and features +# +# CONFIG_XEN_DOM0 is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_EVDEV=y + +# +# Device drivers +# +CONFIG_FB=y + +# +# Character devices +# +CONFIG_VT_HW_CONSOLE_BINDING=y diff --git a/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/uivm.scc b/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/uivm.scc new file mode 100644 index 0000000000..3acf2fc153 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/ktypes/xen/uivm.scc @@ -0,0 +1,3 @@ +include ktypes/xen/pvh.scc + +kconf non-hardware uivm.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/backports/0001-xen-gntdev-switch-from-kcalloc-to-kvcalloc.patch b/recipes-kernel/linux/files/openxt-kmeta/patches/backports/0001-xen-gntdev-switch-from-kcalloc-to-kvcalloc.patch new file mode 100644 index 0000000000..73ccdb2c47 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/backports/0001-xen-gntdev-switch-from-kcalloc-to-kvcalloc.patch @@ -0,0 +1,77 @@ +From b3f7931f5c61ba39e81a5c958bf5d65ebb1838af Mon Sep 17 00:00:00 2001 +From: Juergen Gross +Date: Thu, 7 Nov 2019 12:15:46 +0100 +Subject: [PATCH] xen/gntdev: switch from kcalloc() to kvcalloc() + +With sufficient many pages to map gntdev can reach order 9 allocation +sizes. As there is no need to have physically contiguous buffers switch +to kvcalloc() in order to avoid failing allocations. + +Signed-off-by: Juergen Gross +Reviewed-by: Oleksandr Andrushchenko +Reviewed-by: Boris Ostrovsky +Signed-off-by: Juergen Gross +--- + drivers/xen/gntdev.c | 31 ++++++++++++++++--------------- + 1 file changed, 16 insertions(+), 15 deletions(-) + +diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c +index ad621ec1912c..4fc83e3f5ad3 100644 +--- a/drivers/xen/gntdev.c ++++ b/drivers/xen/gntdev.c +@@ -112,14 +112,14 @@ static void gntdev_free_map(struct gntdev_grant_map *map) + gnttab_free_pages(map->count, map->pages); + + #ifdef CONFIG_XEN_GRANT_DMA_ALLOC +- kfree(map->frames); ++ kvfree(map->frames); + #endif +- kfree(map->pages); +- kfree(map->grants); +- kfree(map->map_ops); +- kfree(map->unmap_ops); +- kfree(map->kmap_ops); +- kfree(map->kunmap_ops); ++ kvfree(map->pages); ++ kvfree(map->grants); ++ kvfree(map->map_ops); ++ kvfree(map->unmap_ops); ++ kvfree(map->kmap_ops); ++ kvfree(map->kunmap_ops); + kfree(map); + } + +@@ -133,12 +133,13 @@ struct gntdev_grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count, + if (NULL == add) + return NULL; + +- add->grants = kcalloc(count, sizeof(add->grants[0]), GFP_KERNEL); +- add->map_ops = kcalloc(count, sizeof(add->map_ops[0]), GFP_KERNEL); +- add->unmap_ops = kcalloc(count, sizeof(add->unmap_ops[0]), GFP_KERNEL); +- add->kmap_ops = kcalloc(count, sizeof(add->kmap_ops[0]), GFP_KERNEL); +- add->kunmap_ops = kcalloc(count, sizeof(add->kunmap_ops[0]), GFP_KERNEL); +- add->pages = kcalloc(count, sizeof(add->pages[0]), GFP_KERNEL); ++ add->grants = kvcalloc(count, sizeof(add->grants[0]), GFP_KERNEL); ++ add->map_ops = kvcalloc(count, sizeof(add->map_ops[0]), GFP_KERNEL); ++ add->unmap_ops = kvcalloc(count, sizeof(add->unmap_ops[0]), GFP_KERNEL); ++ add->kmap_ops = kvcalloc(count, sizeof(add->kmap_ops[0]), GFP_KERNEL); ++ add->kunmap_ops = kvcalloc(count, ++ sizeof(add->kunmap_ops[0]), GFP_KERNEL); ++ add->pages = kvcalloc(count, sizeof(add->pages[0]), GFP_KERNEL); + if (NULL == add->grants || + NULL == add->map_ops || + NULL == add->unmap_ops || +@@ -157,8 +158,8 @@ struct gntdev_grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count, + if (dma_flags & (GNTDEV_DMA_FLAG_WC | GNTDEV_DMA_FLAG_COHERENT)) { + struct gnttab_dma_alloc_args args; + +- add->frames = kcalloc(count, sizeof(add->frames[0]), +- GFP_KERNEL); ++ add->frames = kvcalloc(count, sizeof(add->frames[0]), ++ GFP_KERNEL); + if (!add->frames) + goto err; + +-- +2.28.0 + diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/backports/backports.scc b/recipes-kernel/linux/files/openxt-kmeta/patches/backports/backports.scc new file mode 100644 index 0000000000..cc762cbe65 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/backports/backports.scc @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: MIT +define KFEATURE_DESCRIPTION "Apply backported patches" +define KFEATURE_COMPATIBILITY all + +patch tpm_tis-work-around-status-register-bug-in-STMicroelectronics-TPM.patch +patch 0001-xen-gntdev-switch-from-kcalloc-to-kvcalloc.patch diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/backports/tpm_tis-work-around-status-register-bug-in-STMicroelectronics-TPM.patch b/recipes-kernel/linux/files/openxt-kmeta/patches/backports/tpm_tis-work-around-status-register-bug-in-STMicroelectronics-TPM.patch new file mode 100644 index 0000000000..37a85cd173 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/backports/tpm_tis-work-around-status-register-bug-in-STMicroelectronics-TPM.patch @@ -0,0 +1,38 @@ +From: Omar Sandoval +Subject: [PATCH] tpm_tis: work around status register bug in STMicroelectronics TPM +Date: Wed, 15 Apr 2020 15:45:22 -0700 +Message-Id: <6c55d7c1fb84e5bf2ace9f05ec816ef67bd873e1.1586990595.git.osandov@fb.com> + +We've encountered a particular model of STMicroelectronics TPM that +transiently returns a bad value in the status register. This causes the +kernel to believe that the TPM is ready to receive a command when it +actually isn't, which in turn causes the send to time out in +get_burstcount(). In testing, reading the status register one extra time +convinces the TPM to return a valid value. + +Signed-off-by: Omar Sandoval +--- + drivers/char/tpm/tpm_tis_core.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +--- a/drivers/char/tpm/tpm_tis_core.c ++++ b/drivers/char/tpm/tpm_tis_core.c +@@ -238,6 +238,18 @@ static u8 tpm_tis_status(struct tpm_chip + rc = tpm_tis_read8(priv, TPM_STS(priv->locality), &status); + if (rc < 0) + return 0; ++ /* ++ * Some STMicroelectronics TPMs have a bug where the status register is ++ * sometimes bogus (all 1s) if read immediately after the access ++ * register is written to. Bits 0, 1, and 5 are always supposed to read ++ * as 0, so this is clearly invalid. Reading the register a second time ++ * returns a valid value. ++ */ ++ if (unlikely(status == 0xff)) { ++ rc = tpm_tis_read8(priv, TPM_STS(priv->locality), &status); ++ if (rc < 0) ++ return 0; ++ } + + return status; + } diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/blktap2/blktap2.cfg b/recipes-kernel/linux/files/openxt-kmeta/patches/blktap2/blktap2.cfg new file mode 100644 index 0000000000..76e1996bca --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/blktap2/blktap2.cfg @@ -0,0 +1 @@ +CONFIG_BLK_DEV_TAP=y diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/blktap2/blktap2.patch b/recipes-kernel/linux/files/openxt-kmeta/patches/blktap2/blktap2.patch new file mode 100644 index 0000000000..30404b9205 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/blktap2/blktap2.patch @@ -0,0 +1,3070 @@ +################################################################################ +SHORT DESCRIPTION: +################################################################################ +blktap2 driver. + +################################################################################ +LONG DESCRIPTION: +################################################################################ +The block tap driver allows block device requests to be redirected to +processes, through a device interface. Doing so allows user-space development +of high-performance block storage backends, where disk images may be +implemented as files, in memory, or on other hosts across the network. + +See http://xenbits.xensource.com/hg/xen-unstable.hg/file/tip/tools/blktap2/README. + +################################################################################ +CHANGELOG +################################################################################ +Port to 3.18: Eric Chanudet +Port to 4.14: Richard Turner +Port to 4.19: Richard Turner +Port to 5.4 blk-mq: Jason Andryuk +Restore 4.14 spinlock order + +###############################################################################i +REMOVAL +################################################################################ +This is required for guest block devices support. + +################################################################################ +UPSTREAM PLAN +################################################################################ +None. + +################################################################################ +INTERNAL DEPENDENCIES +################################################################################ +Guest block devices handling. + +################################################################################ +PATCHES +################################################################################ +--- a/drivers/block/Kconfig ++++ b/drivers/block/Kconfig +@@ -469,4 +469,13 @@ config BLK_DEV_RSXX + To compile this driver as a module, choose M here: the + module will be called rsxx. + ++config BLK_DEV_TAP ++ tristate "Blktap userspace devices" ++ help ++ The block tap driver allows block device requests to be ++ redirected to processes, through a device interface. ++ Doing so allows user-space development of high-performance ++ block storage backends, where disk images may be implemented ++ as files, in memory, or on other hosts across the network. ++ + endif # BLK_DEV +--- a/drivers/block/Makefile ++++ b/drivers/block/Makefile +@@ -25,6 +25,7 @@ obj-$(CONFIG_BLK_DEV_UMEM) += umem.o + obj-$(CONFIG_BLK_DEV_NBD) += nbd.o + obj-$(CONFIG_BLK_DEV_CRYPTOLOOP) += cryptoloop.o + obj-$(CONFIG_VIRTIO_BLK) += virtio_blk.o ++obj-$(CONFIG_BLK_DEV_TAP) += blktap/ + + obj-$(CONFIG_BLK_DEV_SX8) += sx8.o + +--- /dev/null ++++ b/drivers/block/blktap/Makefile +@@ -0,0 +1,3 @@ ++obj-$(CONFIG_BLK_DEV_TAP) := blktap.o ++ ++blktap-objs := control.o ring.o device.o request.o sysfs.o +--- /dev/null ++++ b/drivers/block/blktap/blktap.h +@@ -0,0 +1,185 @@ ++#ifndef _BLKTAP_H_ ++#define _BLKTAP_H_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++extern int blktap_debug_level; ++extern int blktap_ring_major; ++extern int blktap_device_major; ++ ++#define BTPRINTK(level, tag, force, _f, _a...) \ ++ do { \ ++ if (blktap_debug_level > level && \ ++ (force || printk_ratelimit())) \ ++ printk(tag "%s: " _f, __func__, ##_a); \ ++ } while (0) ++ ++#define BTDBG(_f, _a...) BTPRINTK(8, KERN_DEBUG, 1, _f, ##_a) ++#define BTINFO(_f, _a...) BTPRINTK(0, KERN_INFO, 0, _f, ##_a) ++#define BTWARN(_f, _a...) BTPRINTK(0, KERN_WARNING, 0, _f, ##_a) ++#define BTERR(_f, _a...) BTPRINTK(0, KERN_ERR, 0, _f, ##_a) ++ ++#define MAX_BLKTAP_DEVICE 1024 ++ ++#define BLKTAP_DEVICE 4 ++#define BLKTAP_DEVICE_CLOSED 5 ++#define BLKTAP_PAUSE_REQUESTED 6 ++#define BLKTAP_PAUSED 7 ++#define BLKTAP_SHUTDOWN_REQUESTED 8 ++ ++#define BLKTAP_REQUEST_FREE 0 ++#define BLKTAP_REQUEST_PENDING 1 ++ ++#define BLKTAP2_RING_MESSAGE_PAUSE 1 ++#define BLKTAP2_RING_MESSAGE_RESUME 2 ++ ++struct blktap_device { ++ struct mutex lock; ++ struct gendisk *gd; ++ struct request_queue *rq; ++ struct blk_mq_tag_set tag_set; ++}; ++ ++struct blktap_request; ++ ++struct blktap_ring { ++ struct task_struct *task; ++ ++ struct vm_area_struct *vma; ++ struct blktap_front_ring ring; ++ unsigned long ring_vstart; ++ unsigned long user_vstart; ++ ++ int response; ++ ++ /* pending doesn't have any locking, but that is okay. Insertions ++ * happen under blktap_device->lock, so that is serialized. Removal ++ * uses the blktap_request->usr_idx, so they aren't iterating the ++ * array. As long as pointer assignments are atomic, then you don't ++ * have to worry about Insertion and Removal racing. In practice, ++ * there are simultaneous operations, so n_pending needs to be ++ * atomic_t to keep those in sync. */ ++ atomic_t n_pending; ++ struct blktap_request *pending[BLKTAP_RING_SIZE]; ++ ++ wait_queue_head_t poll_wait; ++ ++ dev_t devno; ++ struct device *dev; ++}; ++ ++struct blktap_statistics { ++ unsigned long st_print; ++ int st_rd_req; ++ int st_wr_req; ++ int st_tr_req; ++ int st_oo_req; ++ int st_fl_req; ++ int st_rd_sect; ++ int st_wr_sect; ++ int st_tr_sect; ++ s64 st_rd_cnt; ++ s64 st_rd_sum_usecs; ++ s64 st_rd_max_usecs; ++ s64 st_wr_cnt; ++ s64 st_wr_sum_usecs; ++ s64 st_wr_max_usecs; ++}; ++ ++struct blktap_request { ++ struct blktap *tap; ++ struct request *rq; ++ int usr_idx; ++ ++ int operation; ++ ++ struct scatterlist sg_table[BLKTAP_SEGMENT_MAX]; ++ struct page *pages[BLKTAP_SEGMENT_MAX]; ++ int nr_pages; ++}; ++ ++#define blktap_for_each_sg(_sg, _req, _i) \ ++ for (_sg = (_req)->sg_table, _i = 0; \ ++ _i < (_req)->nr_pages; \ ++ (_sg)++, (_i)++) ++ ++struct blktap { ++ int minor; ++ unsigned long dev_inuse; ++ ++ struct blktap_ring ring; ++ struct blktap_device device; ++ struct blktap_page_pool *pool; ++ ++ wait_queue_head_t remove_wait; ++ struct work_struct remove_work; ++ struct delayed_work destroy_work; ++ char name[BLKTAP_NAME_MAX]; ++ ++ struct blktap_statistics stats; ++}; ++ ++struct blktap_page_pool { ++ struct mempool_s *bufs; ++ spinlock_t lock; ++ struct kobject kobj; ++ wait_queue_head_t wait; ++}; ++ ++extern struct mutex blktap_lock; ++extern struct blktap **blktaps; ++extern int blktap_max_minor; ++ ++int blktap_control_destroy_tap(struct blktap *); ++size_t blktap_control_debug(struct blktap *, char *, size_t); ++ ++int blktap_ring_init(void); ++void blktap_ring_exit(void); ++size_t blktap_ring_debug(struct blktap *, char *, size_t); ++int blktap_ring_create(struct blktap *); ++int blktap_ring_destroy(struct blktap *); ++int blktap_ring_pause(struct blktap *); ++int blktap_ring_resume(struct blktap *); ++struct blktap_request *blktap_ring_make_request(struct blktap *); ++void blktap_ring_free_request(struct blktap *,struct blktap_request *); ++void blktap_ring_submit_request(struct blktap *, struct blktap_request *); ++int blktap_ring_map_request_segment(struct blktap *, struct blktap_request *, int); ++int blktap_ring_map_request(struct blktap *, struct blktap_request *); ++void blktap_ring_unmap_request(struct blktap *, struct blktap_request *); ++void blktap_ring_kick_user(struct blktap *); ++ ++int blktap_sysfs_init(void); ++void blktap_sysfs_exit(void); ++int blktap_sysfs_create(struct blktap *); ++void blktap_sysfs_destroy(struct blktap *); ++ ++int blktap_device_init(void); ++void blktap_device_exit(void); ++size_t blktap_device_debug(struct blktap *, char *, size_t); ++int blktap_device_create(struct blktap *, struct blktap_device_info *); ++void blktap_device_configure(struct blktap *tap, struct blktap_device_info *info); ++int blktap_device_destroy(struct blktap *); ++int blktap_device_try_destroy(struct blktap *tap); ++int blktap_device_pause(struct blktap *); ++int blktap_device_resume(struct blktap *tap); ++void blktap_device_run_queues(struct blktap *); ++void blktap_device_end_request(struct blktap *, struct blktap_request *, blk_status_t); ++ ++int blktap_page_pool_init(struct kobject *); ++void blktap_page_pool_exit(void); ++struct blktap_page_pool *blktap_page_pool_get(const char *); ++ ++size_t blktap_request_debug(struct blktap *, char *, size_t); ++struct blktap_request *blktap_request_alloc(struct blktap *); ++int blktap_request_get_pages(struct blktap *, struct blktap_request *, int); ++void blktap_request_free(struct blktap *, struct blktap_request *); ++void blktap_request_bounce(struct blktap *, struct blktap_request *, int, int); ++ ++ ++#endif +--- /dev/null ++++ b/drivers/block/blktap/control.c +@@ -0,0 +1,360 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "blktap.h" ++ ++DEFINE_MUTEX(blktap_lock); ++ ++struct blktap **blktaps; ++int blktap_max_minor; ++static struct blktap_page_pool *default_pool; ++ ++static struct blktap * ++blktap_control_get_minor(void) ++{ ++ int minor; ++ struct blktap *tap; ++ ++ tap = kzalloc(sizeof(*tap), GFP_KERNEL); ++ if (unlikely(!tap)) ++ return NULL; ++ ++ mutex_lock(&blktap_lock); ++ ++ for (minor = 0; minor < blktap_max_minor; minor++) ++ if (!blktaps[minor]) ++ break; ++ ++ if (minor == MAX_BLKTAP_DEVICE) ++ goto fail; ++ ++ if (minor == blktap_max_minor) { ++ void *p; ++ int n; ++ ++ n = min(2 * blktap_max_minor, MAX_BLKTAP_DEVICE); ++ p = krealloc(blktaps, n * sizeof(blktaps[0]), GFP_KERNEL); ++ if (!p) ++ goto fail; ++ ++ blktaps = p; ++ minor = blktap_max_minor; ++ blktap_max_minor = n; ++ ++ memset(&blktaps[minor], 0, (n - minor) * sizeof(blktaps[0])); ++ } ++ ++ tap->minor = minor; ++ blktaps[minor] = tap; ++ ++ __module_get(THIS_MODULE); ++out: ++ mutex_unlock(&blktap_lock); ++ return tap; ++ ++fail: ++ mutex_unlock(&blktap_lock); ++ kfree(tap); ++ tap = NULL; ++ goto out; ++} ++ ++static void ++blktap_control_put_minor(struct blktap* tap) ++{ ++ blktaps[tap->minor] = NULL; ++ kfree(tap); ++ ++ module_put(THIS_MODULE); ++} ++ ++static struct blktap* ++blktap_control_create_tap(void) ++{ ++ struct blktap *tap; ++ int err; ++ ++ tap = blktap_control_get_minor(); ++ if (!tap) ++ return NULL; ++ ++ kobject_get(&default_pool->kobj); ++ tap->pool = default_pool; ++ mutex_init(&tap->device.lock); ++ ++ err = blktap_ring_create(tap); ++ if (err) ++ goto fail_tap; ++ ++ err = blktap_sysfs_create(tap); ++ if (err) ++ goto fail_ring; ++ ++ return tap; ++ ++fail_ring: ++ blktap_ring_destroy(tap); ++fail_tap: ++ blktap_control_put_minor(tap); ++ ++ return NULL; ++} ++ ++int ++blktap_control_destroy_tap(struct blktap *tap) ++{ ++ int err; ++ ++ err = blktap_ring_destroy(tap); ++ if (err) ++ return err; ++ ++ kobject_put(&tap->pool->kobj); ++ ++ blktap_sysfs_destroy(tap); ++ ++ blktap_control_put_minor(tap); ++ return err; ++} ++ ++static void ++blktap_control_remove_work(struct work_struct *work) ++{ ++ struct blktap *tap ++ = container_of(work, struct blktap, remove_work); ++ blktap_control_destroy_tap(tap); ++} ++ ++static int ++blktap_control_destroy_tap_ioctl(int minor) ++{ ++ struct blktap *tap; ++ struct blktap_ring *ring; ++ int r; ++ ++ tap = blktaps[minor]; ++ if (!tap) ++ return -ENODEV; ++ ++ ring = &tap->ring; ++ ++ if (ring->vma == NULL && atomic_read(&ring->n_pending)) ++ printk(KERN_WARNING ++ "blktap%d ring not mapped and n_pending %d\n", ++ minor, atomic_read(&ring->n_pending)); ++ ++ r = wait_event_interruptible(tap->remove_wait, ++ atomic_read(&ring->n_pending) == 0 || ++ ring->vma == NULL); ++ if (r == -ERESTARTSYS) ++ return -EAGAIN; ++ ++ if (test_and_set_bit(BLKTAP_SHUTDOWN_REQUESTED, &tap->dev_inuse)) ++ return 0; ++ ++ if (tap->ring.vma) { ++ struct blktap_sring *sring = ring->ring.sring; ++ ++ *BLKTAP_RING_MESSAGE(sring) = BLKTAP_RING_MESSAGE_CLOSE; ++ blktap_ring_kick_user(tap); ++ } else { ++ INIT_WORK(&tap->remove_work, blktap_control_remove_work); ++ schedule_work(&tap->remove_work); ++ } ++ ++ return 0; ++} ++ ++static long ++blktap_control_ioctl(struct file *filp, ++ unsigned int cmd, unsigned long arg) ++{ ++ struct blktap *tap; ++ ++ switch (cmd) { ++ case BLKTAP_IOCTL_ALLOC_TAP: { ++ struct blktap_info info; ++ void __user *ptr = (void __user*)arg; ++ ++ tap = blktap_control_create_tap(); ++ if (!tap) ++ return -ENOMEM; ++ ++ info.ring_major = blktap_ring_major; ++ info.bdev_major = blktap_device_major; ++ info.ring_minor = tap->minor; ++ ++ if (copy_to_user(ptr, &info, sizeof(info))) { ++ blktap_control_destroy_tap(tap); ++ return -EFAULT; ++ } ++ ++ return 0; ++ } ++ ++ case BLKTAP_IOCTL_FREE_TAP: { ++ int minor = arg; ++ ++ if (minor > MAX_BLKTAP_DEVICE) ++ return -EINVAL; ++ ++ return blktap_control_destroy_tap_ioctl(minor); ++ } ++ } ++ ++ return -ENOIOCTLCMD; ++} ++ ++static struct file_operations blktap_control_file_operations = { ++ .owner = THIS_MODULE, ++ .unlocked_ioctl = blktap_control_ioctl, ++}; ++ ++static struct miscdevice blktap_control = { ++ .minor = MISC_DYNAMIC_MINOR, ++ .name = "blktap-control", ++ .fops = &blktap_control_file_operations, ++}; ++ ++static struct device *control_device; ++ ++static ssize_t ++blktap_control_show_default_pool(struct device *device, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ return sprintf(buf, "%s", kobject_name(&default_pool->kobj)); ++} ++ ++static ssize_t ++blktap_control_store_default_pool(struct device *device, ++ struct device_attribute *attr, ++ const char *buf, size_t size) ++{ ++ struct blktap_page_pool *pool, *tmp = default_pool; ++ ++ pool = blktap_page_pool_get(buf); ++ if (IS_ERR(pool)) ++ return PTR_ERR(pool); ++ ++ default_pool = pool; ++ kobject_put(&tmp->kobj); ++ ++ return size; ++} ++ ++static DEVICE_ATTR(default_pool, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, ++ blktap_control_show_default_pool, ++ blktap_control_store_default_pool); ++ ++size_t ++blktap_control_debug(struct blktap *tap, char *buf, size_t size) ++{ ++ char *s = buf, *end = buf + size; ++ ++ s += snprintf(s, end - s, ++ "tap %u:%u name:'%s' flags:%#08lx\n", ++ MAJOR(tap->ring.devno), MINOR(tap->ring.devno), ++ tap->name, tap->dev_inuse); ++ ++ return s - buf; ++} ++ ++static int __init ++blktap_control_init(void) ++{ ++ int err; ++ ++ err = misc_register(&blktap_control); ++ if (err) ++ return err; ++ ++ control_device = blktap_control.this_device; ++ ++ blktap_max_minor = min(64, MAX_BLKTAP_DEVICE); ++ blktaps = kzalloc(blktap_max_minor * sizeof(blktaps[0]), GFP_KERNEL); ++ if (!blktaps) { ++ BTERR("failed to allocate blktap minor map"); ++ return -ENOMEM; ++ } ++ ++ err = blktap_page_pool_init(&control_device->kobj); ++ if (err) ++ return err; ++ ++ default_pool = blktap_page_pool_get("default"); ++ if (!default_pool) ++ return -ENOMEM; ++ ++ err = device_create_file(control_device, &dev_attr_default_pool); ++ if (err) ++ return err; ++ ++ return 0; ++} ++ ++static void ++blktap_control_exit(void) ++{ ++ if (default_pool) { ++ kobject_put(&default_pool->kobj); ++ default_pool = NULL; ++ } ++ ++ blktap_page_pool_exit(); ++ ++ if (blktaps) { ++ kfree(blktaps); ++ blktaps = NULL; ++ } ++ ++ if (control_device) { ++ misc_deregister(&blktap_control); ++ control_device = NULL; ++ } ++} ++ ++static void ++blktap_exit(void) ++{ ++ blktap_control_exit(); ++ blktap_ring_exit(); ++ blktap_sysfs_exit(); ++ blktap_device_exit(); ++} ++ ++static int __init ++blktap_init(void) ++{ ++ int err; ++ ++ err = blktap_device_init(); ++ if (err) ++ goto fail; ++ ++ err = blktap_ring_init(); ++ if (err) ++ goto fail; ++ ++ err = blktap_sysfs_init(); ++ if (err) ++ goto fail; ++ ++ err = blktap_control_init(); ++ if (err) ++ goto fail; ++ ++ return 0; ++ ++fail: ++ blktap_exit(); ++ return err; ++} ++ ++module_init(blktap_init); ++module_exit(blktap_exit); ++MODULE_LICENSE("Dual BSD/GPL"); +--- /dev/null ++++ b/drivers/block/blktap/device.c +@@ -0,0 +1,710 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "blktap.h" ++ ++int blktap_device_major; ++ ++#define dev_to_blktap(_dev) container_of(_dev, struct blktap, device) ++ ++struct blktap_req { ++ blk_status_t error; ++}; ++ ++static inline struct blktap_req *blktap_req(struct request *rq) ++{ ++ return blk_mq_rq_to_pdu(rq); ++} ++ ++static int ++blktap_device_open(struct block_device *bdev, fmode_t mode) ++{ ++ struct gendisk *disk = bdev->bd_disk; ++ struct blktap_device *tapdev = disk->private_data; ++ ++ if (!tapdev) ++ return -ENXIO; ++ ++ /* NB. we might have bounced a bd trylock by tapdisk. when ++ * failing for reasons not !tapdev, make sure to kick tapdisk ++ * out of destroy wait state again. */ ++ ++ return 0; ++} ++ ++static void ++blktap_device_release(struct gendisk *disk, fmode_t mode) ++{ ++ struct blktap_device *tapdev = disk->private_data; ++ struct block_device *bdev = bdget_disk(disk, 0); ++ struct blktap *tap = dev_to_blktap(tapdev); ++ ++ bdput(bdev); ++ ++ if (!bdev->bd_openers) { ++ set_bit(BLKTAP_DEVICE_CLOSED, &tap->dev_inuse); ++ blktap_ring_kick_user(tap); ++ } ++} ++ ++static int ++blktap_device_getgeo(struct block_device *bd, struct hd_geometry *hg) ++{ ++ /* We don't have real geometry info, but let's at least return ++ values consistent with the size of the device */ ++ sector_t nsect = get_capacity(bd->bd_disk); ++ sector_t cylinders = nsect; ++ ++ hg->heads = 0xff; ++ hg->sectors = 0x3f; ++ sector_div(cylinders, hg->heads * hg->sectors); ++ hg->cylinders = cylinders; ++ if ((sector_t)(hg->cylinders + 1) * hg->heads * hg->sectors < nsect) ++ hg->cylinders = 0xffff; ++ return 0; ++} ++ ++static int ++blktap_device_ioctl(struct block_device *bd, fmode_t mode, ++ unsigned command, unsigned long argument) ++{ ++ int i; ++ ++ switch (command) { ++ case CDROMMULTISESSION: ++ BTDBG("FIXME: support multisession CDs later\n"); ++ for (i = 0; i < sizeof(struct cdrom_multisession); i++) ++ if (put_user(0, (char __user *)(argument + i))) ++ return -EFAULT; ++ return 0; ++ ++ case SCSI_IOCTL_GET_IDLUN: ++ if (!access_ok(argument, sizeof(struct scsi_idlun))) ++ return -EFAULT; ++ ++ /* return 0 for now. */ ++ __put_user(0, &((struct scsi_idlun __user *)argument)->dev_id); ++ __put_user(0, ++ &((struct scsi_idlun __user *)argument)->host_unique_id); ++ return 0; ++ ++ default: ++ /*printk(KERN_ALERT "ioctl %08x not supported by Xen blkdev\n", ++ command);*/ ++ return -EINVAL; /* same return as native Linux */ ++ } ++ ++ return 0; ++} ++ ++static struct block_device_operations blktap_device_file_operations = { ++ .owner = THIS_MODULE, ++ .open = blktap_device_open, ++ .release = blktap_device_release, ++ .ioctl = blktap_device_ioctl, ++ .getgeo = blktap_device_getgeo ++}; ++ ++void ++blktap_device_end_request(struct blktap *tap, ++ struct blktap_request *request, ++ blk_status_t error) ++{ ++ struct blktap_device *tapdev = &tap->device; ++ struct request *rq = request->rq; ++ ++ blktap_ring_unmap_request(tap, request); ++ ++ blktap_ring_free_request(tap, request); ++ ++ dev_dbg(disk_to_dev(tapdev->gd), ++ "end_request: op=%d error=%d bytes=%d\n", ++ rq_data_dir(rq), error, blk_rq_bytes(rq)); ++ ++ blk_mq_end_request(rq, error); ++} ++ ++int ++blktap_device_make_request(struct blktap *tap, struct request *rq) ++{ ++ struct blktap_device *tapdev = &tap->device; ++ struct blktap_request *request; ++ int nsegs; ++ int err; ++ ++ request = blktap_ring_make_request(tap); ++ if (IS_ERR(request)) { ++ err = PTR_ERR(request); ++ request = NULL; ++ ++ if (err == -ENOSPC || err == -ENOMEM) ++ goto stop; ++ ++ goto fail; ++ } ++ ++ if (blk_rq_is_passthrough(rq)) { ++ err = -EOPNOTSUPP; ++ goto fail; ++ } ++ ++ switch (req_op(rq)) { ++ case REQ_OP_DISCARD: ++ request->operation = BLKTAP_OP_TRIM; ++ request->nr_pages = 0; ++ goto submit; ++ case REQ_OP_FLUSH: ++ request->operation = BLKTAP_OP_FLUSH; ++ request->nr_pages = 0; ++ goto submit; ++ case REQ_OP_READ: ++ request->operation = BLKTAP_OP_READ; ++ break; ++ case REQ_OP_WRITE: ++ request->operation = BLKTAP_OP_WRITE; ++ break; ++ default: ++ err = -EOPNOTSUPP; ++ goto fail; ++ } ++ ++ nsegs = blk_rq_map_sg(rq->q, rq, request->sg_table); ++ ++ err = blktap_request_get_pages(tap, request, nsegs); ++ if (err) ++ goto stop; ++ ++ err = blktap_ring_map_request(tap, request); ++ if (err) ++ goto fail; ++ ++submit: ++ request->rq = rq; ++ blktap_ring_submit_request(tap, request); ++ ++ return 0; ++ ++stop: ++ tap->stats.st_oo_req++; ++ err = -EBUSY; ++ ++_out: ++ if (request) ++ blktap_ring_free_request(tap, request); ++ ++ return err; ++fail: ++ if (printk_ratelimit()) ++ dev_warn(disk_to_dev(tapdev->gd), ++ "make request: %d, failing\n", err); ++ goto _out; ++} ++ ++static void cleanup_queue(struct request_queue *rq) ++{ ++ struct blktap *tap = rq->queuedata; ++ struct blktap_device *tapdev = &tap->device; ++ ++ blk_cleanup_queue(rq); ++ blk_mq_free_tag_set(&tapdev->tag_set); ++} ++ ++void blktap_device_run_queues(struct blktap *tap) ++{ ++ struct blktap_device *tapdev = &tap->device; ++ ++ if (!tapdev->gd) ++ return; ++ ++ if (!RING_FULL(&tap->ring.ring)) ++ blk_mq_start_stopped_hw_queues(tapdev->gd->queue, true); ++} ++ ++static void ++blktap_device_restart(struct blktap *tap) ++{ ++ struct blktap_device *dev; ++ ++ dev = &tap->device; ++ ++ mutex_lock(&dev->lock); ++ ++ /* Re-enable calldowns. */ ++ if (dev->gd) { ++ struct request_queue *rq = dev->gd->queue; ++ ++ if (blk_queue_stopped(rq)) ++ blk_mq_start_hw_queues(rq); ++ ++ /* Kick things off immediately. */ ++ blktap_ring_kick_user(tap); ++ } ++ ++ mutex_unlock(&dev->lock); ++} ++ ++void ++blktap_device_configure(struct blktap *tap, ++ struct blktap_device_info *info) ++{ ++ struct blktap_device *tapdev = &tap->device; ++ struct gendisk *gd = tapdev->gd; ++ struct request_queue *rq = gd->queue; ++ struct queue_limits *limits = &rq->limits; ++ ++ set_capacity(gd, info->capacity); ++ set_disk_ro(gd, !!(info->flags & BLKTAP_DEVICE_FLAG_RO)); ++ ++ blk_queue_flag_set(QUEUE_FLAG_VIRT, rq); ++ blk_queue_logical_block_size(rq, info->sector_size); ++ ++ /* Hard sector size and alignment in hardware */ ++ blk_queue_physical_block_size(rq, info->phys_block_size); ++ blk_queue_alignment_offset(rq, info->phys_block_offset); ++ ++ /* Each segment in a request is up to an aligned page in size. */ ++ blk_queue_segment_boundary(rq, PAGE_SIZE - 1); ++ blk_queue_max_segment_size(rq, PAGE_SIZE); ++ ++ /* Ensure a merged request will fit in a single I/O ring slot. */ ++ blk_queue_max_segments(rq, BLKTAP_SEGMENT_MAX); ++ blk_queue_max_segment_size(rq, PAGE_SIZE); ++ ++ /* Make sure buffer addresses are sector-aligned. */ ++ blk_queue_dma_alignment(rq, 511); ++ ++ /* Make sure there is buffer control on high memory pages */ ++ blk_queue_bounce_limit(rq, BLK_BOUNCE_HIGH); ++ ++ /* Enable cache control */ ++ if (info->flags & BLKTAP_DEVICE_FLAG_FLUSH) ++ blk_queue_write_cache(rq, true, false); ++ ++ /* Block discards */ ++ if (info->flags & BLKTAP_DEVICE_FLAG_TRIM) { ++ blk_queue_max_discard_sectors(rq, UINT_MAX); ++ ++ limits->discard_granularity = info->trim_block_size; ++ limits->discard_alignment = info->trim_block_offset; ++ ++ blk_queue_flag_set(QUEUE_FLAG_DISCARD, rq); ++ } ++} ++ ++static int ++blktap_device_validate_info(struct blktap *tap, ++ struct blktap_device_info *info) ++{ ++ struct device *dev = tap->ring.dev; ++ ++ /* sector size is is 2^(n >= 9) */ ++ if (info->sector_size < 512 || ++ !is_power_of_2(info->sector_size)) ++ goto fail; ++ ++ /* make sure capacity won't overflow */ ++ if (!info->capacity || ++ info->capacity > ULLONG_MAX >> ilog2(info->sector_size)) ++ goto fail; ++ ++ /* physical blocks default to logical ones */ ++ if (!(info->flags & BLKTAP_DEVICE_FLAG_PSZ)) { ++ info->phys_block_size = info->sector_size; ++ info->phys_block_offset = 0; ++ } ++ ++ /* phys block size is 2^n and >= logical */ ++ if (info->phys_block_size < info->sector_size || ++ !is_power_of_2(info->phys_block_size)) ++ goto fail; ++ ++ /* alignment offset < physical/logical */ ++ if (info->phys_block_offset % info->sector_size || ++ info->phys_block_offset >= info->phys_block_size) ++ goto fail; ++ ++ /* trim info vs logical addressing */ ++ if (info->flags & BLKTAP_DEVICE_FLAG_TRIM) { ++ ++ if (info->trim_block_size < info->sector_size || ++ !is_power_of_2(info->trim_block_size)) ++ goto fail; ++ ++ if (info->trim_block_offset % info->sector_size || ++ info->trim_block_offset >= info->trim_block_size) ++ goto fail; ++ } ++ ++ return 0; ++ ++fail: ++ dev_err(dev, ++ "capacity: %llu, sector-size: %u/%u+%u, " ++ "trim: %u+%u flags: %#lx\n", ++ info->capacity, info->sector_size, ++ info->phys_block_size, info->phys_block_offset, ++ info->trim_block_size, info->trim_block_offset, ++ info->flags); ++ return -EINVAL; ++} ++ ++int ++blktap_device_resume(struct blktap *tap) ++{ ++ int err; ++ ++ if (!test_bit(BLKTAP_DEVICE, &tap->dev_inuse)) ++ return -ENODEV; ++ ++ if (!test_bit(BLKTAP_PAUSED, &tap->dev_inuse)) ++ return 0; ++ ++ err = blktap_ring_resume(tap); ++ if (err) ++ return err; ++ ++ BTDBG("restarting device\n"); ++ blktap_device_restart(tap); ++ ++ return 0; ++} ++ ++int ++blktap_device_pause(struct blktap *tap) ++{ ++ struct blktap_device *dev = &tap->device; ++ ++ if (!test_bit(BLKTAP_DEVICE, &tap->dev_inuse)) ++ return -ENODEV; ++ ++ if (test_bit(BLKTAP_PAUSED, &tap->dev_inuse)) ++ return 0; ++ ++ mutex_lock(&dev->lock); ++ ++ blk_mq_stop_hw_queues(dev->gd->queue); ++ set_bit(BLKTAP_PAUSE_REQUESTED, &tap->dev_inuse); ++ ++ mutex_unlock(&dev->lock); ++ ++ return blktap_ring_pause(tap); ++} ++ ++int ++blktap_device_destroy(struct blktap *tap) ++{ ++ struct blktap_device *tapdev = &tap->device; ++ struct block_device *bdev; ++ struct gendisk *gd; ++ int err; ++ ++ gd = tapdev->gd; ++ if (!gd) ++ return 0; ++ ++ bdev = bdget_disk(gd, 0); ++ ++ err = !mutex_trylock(&bdev->bd_mutex); ++ if (err) { ++ /* NB. avoid a deadlock. the last opener syncs the ++ * bdev holding bd_mutex. */ ++ err = -EBUSY; ++ goto out_nolock; ++ } ++ ++ if (bdev->bd_openers) { ++ err = -EBUSY; ++ goto out; ++ } ++ ++ blk_mq_stop_hw_queues(tapdev->rq); ++ ++ del_gendisk(gd); ++ gd->private_data = NULL; ++ ++ cleanup_queue(gd->queue); ++ ++ put_disk(gd); ++ tapdev->gd = NULL; ++ ++ clear_bit(BLKTAP_DEVICE, &tap->dev_inuse); ++ ++ if (test_bit(BLKTAP_SHUTDOWN_REQUESTED, &tap->dev_inuse)) ++ blktap_control_destroy_tap(tap); ++ ++ err = 0; ++out: ++ mutex_unlock(&bdev->bd_mutex); ++out_nolock: ++ bdput(bdev); ++ ++ return err; ++} ++ ++static void ++blktap_device_fail_queue(struct blktap *tap) ++{ ++ struct blktap_device *tapdev = &tap->device; ++ struct request_queue *q = tapdev->gd->queue; ++ ++ mutex_lock(&tapdev->lock); ++ // Moved inside lock like it was in 4.14 ++ blk_queue_flag_clear(QUEUE_FLAG_STOPPED, q); ++ cleanup_queue(tapdev->gd->queue); ++ ++ mutex_unlock(&tapdev->lock); ++} ++ ++int ++blktap_device_try_destroy(struct blktap *tap) ++{ ++ int err; ++ ++ err = blktap_device_destroy(tap); ++ if (err) ++ blktap_device_fail_queue(tap); ++ ++ return err; ++} ++ ++static inline void flush_requests(struct blktap *tap) ++{ ++ struct blktap_ring *rinfo = &tap->ring; ++ ++ RING_PUSH_REQUESTS(&rinfo->ring); ++ ++ blktap_ring_kick_user(tap); ++} ++ ++static blk_status_t blktap_queue_rq(struct blk_mq_hw_ctx *hctx, ++ const struct blk_mq_queue_data *qd) ++{ ++ struct blktap *tap = hctx->queue->queuedata; ++ struct blktap_device *tapdev = &tap->device; ++ struct blktap_ring *rinfo = &tap->ring; ++ ++ blk_mq_start_request(qd->rq); ++ mutex_lock(&tapdev->lock); ++ if (RING_FULL(&rinfo->ring)) ++ goto out_busy; ++ ++ switch (blktap_device_make_request(tap, qd->rq)) { ++ case -EBUSY: ++ goto out_busy; ++ break; ++ case -EOPNOTSUPP: ++ goto out_err; ++ break; ++ case 0: ++ break; ++ } ++ ++ if (qd->last) ++ flush_requests(tap); ++ ++ mutex_unlock(&tapdev->lock); ++ return BLK_STS_OK; ++ ++// EOPNOTSUPP ++out_err: ++ mutex_unlock(&tapdev->lock); ++ return BLK_STS_IOERR; ++ ++out_busy: ++ blk_mq_stop_hw_queue(hctx); ++ mutex_unlock(&tapdev->lock); ++ return BLK_STS_DEV_RESOURCE; ++} ++ ++static void blktap_complete_rq(struct request *rq) ++{ ++ blk_mq_end_request(rq, blktap_req(rq)->error); ++} ++ ++static void blktap_commit_rqs(struct blk_mq_hw_ctx *hctx) ++{ ++ struct blktap *tap = hctx->queue->queuedata; ++ ++ flush_requests(tap); ++} ++ ++static const struct blk_mq_ops blktap_mq_ops = { ++ .queue_rq = blktap_queue_rq, ++ .complete = blktap_complete_rq, ++ .commit_rqs = blktap_commit_rqs, ++}; ++ ++static struct request_queue *init_queue(struct blktap *tap) ++{ ++ struct blktap_device *tapdev = &tap->device; ++ struct request_queue *rq; ++ ++ memset(&tapdev->tag_set, 0, sizeof(tapdev->tag_set)); ++ tapdev->tag_set.ops = &blktap_mq_ops; ++ tapdev->tag_set.nr_hw_queues = 1; ++ tapdev->tag_set.queue_depth = BLKTAP_RING_SIZE / 2; ++ tapdev->tag_set.numa_node = NUMA_NO_NODE; ++ tapdev->tag_set.flags = BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_BLOCKING; ++ tapdev->tag_set.cmd_size = 0; ++ tapdev->tag_set.driver_data = tap; ++ ++ if (blk_mq_alloc_tag_set(&tapdev->tag_set)) ++ return NULL; ++ ++ rq = blk_mq_init_queue(&tapdev->tag_set); ++ if (IS_ERR(rq)) { ++ blk_mq_free_tag_set(&tapdev->tag_set); ++ return rq; ++ } ++ ++ rq->queuedata = tap; ++ ++ tapdev->rq = rq; ++ ++ return rq; ++} ++ ++int ++blktap_device_create(struct blktap *tap, struct blktap_device_info *info) ++{ ++ int minor, err; ++ struct gendisk *gd; ++ struct request_queue *rq; ++ struct blktap_device *tapdev; ++ ++ gd = NULL; ++ rq = NULL; ++ tapdev = &tap->device; ++ minor = tap->minor; ++ ++ if (test_bit(BLKTAP_DEVICE, &tap->dev_inuse)) ++ return -EEXIST; ++ ++ if (blktap_device_validate_info(tap, info)) ++ return -EINVAL; ++ ++ gd = alloc_disk(1); ++ if (!gd) { ++ err = -ENOMEM; ++ goto fail; ++ } ++ ++ if (minor < 26) { ++ sprintf(gd->disk_name, "td%c", 'a' + minor % 26); ++ } else if (minor < (26 + 1) * 26) { ++ sprintf(gd->disk_name, "td%c%c", ++ 'a' + minor / 26 - 1,'a' + minor % 26); ++ } else { ++ const unsigned int m1 = (minor / 26 - 1) / 26 - 1; ++ const unsigned int m2 = (minor / 26 - 1) % 26; ++ const unsigned int m3 = minor % 26; ++ sprintf(gd->disk_name, "td%c%c%c", ++ 'a' + m1, 'a' + m2, 'a' + m3); ++ } ++ ++ gd->major = blktap_device_major; ++ gd->first_minor = minor; ++ gd->fops = &blktap_device_file_operations; ++ gd->private_data = tapdev; ++ ++ rq = init_queue(tap); ++ if (!rq) { ++ err = -ENOMEM; ++ goto fail; ++ } ++ ++ gd->queue = rq; ++ tapdev->gd = gd; ++ ++ blktap_device_configure(tap, info); ++ add_disk(gd); ++ ++ set_bit(BLKTAP_DEVICE, &tap->dev_inuse); ++ ++ dev_info(disk_to_dev(gd), ++ "sector-size: %u/%u+%u capacity: %llu" ++ " discard: %u+%u flush: %#lx\n", ++ queue_logical_block_size(rq), ++ queue_physical_block_size(rq), ++ queue_alignment_offset(rq), ++ (unsigned long long)get_capacity(gd), ++ rq->limits.discard_granularity, ++ queue_discard_alignment(rq), ++ rq->queue_flags); ++ ++ return 0; ++ ++fail: ++ if (gd) ++ del_gendisk(gd); ++ if (rq) ++ cleanup_queue(rq); ++ ++ return err; ++} ++ ++size_t ++blktap_device_debug(struct blktap *tap, char *buf, size_t size) ++{ ++ struct gendisk *disk = tap->device.gd; ++ struct request_queue *q; ++ struct block_device *bdev; ++ char *s = buf, *end = buf + size; ++ ++ if (!disk) ++ return 0; ++ ++ q = disk->queue; ++ ++ s += snprintf(s, end - s, ++ "disk capacity:%llu sector size:%u\n", ++ (unsigned long long)get_capacity(disk), ++ queue_logical_block_size(q)); ++ ++ s += snprintf(s, end - s, ++ "queue flags:%#lx stopped:%d\n", ++ q->queue_flags, blk_queue_stopped(q)); ++ ++ bdev = bdget_disk(disk, 0); ++ if (bdev) { ++ s += snprintf(s, end - s, ++ "bdev openers:%d closed:%d\n", ++ bdev->bd_openers, ++ test_bit(BLKTAP_DEVICE_CLOSED, &tap->dev_inuse)); ++ bdput(bdev); ++ } ++ ++ return s - buf; ++} ++ ++int __init ++blktap_device_init() ++{ ++ int major; ++ ++ /* Dynamically allocate a major for this device */ ++ major = register_blkdev(0, "tapdev"); ++ if (major < 0) { ++ BTERR("Couldn't register blktap device\n"); ++ return -ENOMEM; ++ } ++ ++ blktap_device_major = major; ++ BTINFO("blktap device major %d\n", major); ++ ++ return 0; ++} ++ ++void ++blktap_device_exit(void) ++{ ++ if (blktap_device_major) ++ unregister_blkdev(blktap_device_major, "tapdev"); ++} +--- /dev/null ++++ b/drivers/block/blktap/request.c +@@ -0,0 +1,427 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "blktap.h" ++ ++/* max pages per shared pool. just to prevent accidental dos. */ ++#define POOL_MAX_PAGES (256*BLKTAP_SEGMENT_MAX) ++ ++/* default page pool size. when considering to shrink a shared pool, ++ * note that paused tapdisks may grab a whole lot of pages for a long ++ * time. */ ++#define POOL_DEFAULT_PAGES (2 * BLKTAP_RING_SIZE * BLKTAP_SEGMENT_MAX) ++ ++/* max number of pages allocatable per request. */ ++#define POOL_MAX_REQUEST_PAGES BLKTAP_SEGMENT_MAX ++ ++/* min request structs per pool. These grow dynamically. */ ++#define POOL_MIN_REQS BLKTAP_RING_SIZE ++ ++static struct kset *pool_set; ++ ++#define kobj_to_pool(_kobj) \ ++ container_of(_kobj, struct blktap_page_pool, kobj) ++ ++static struct kmem_cache *request_cache; ++static mempool_t *request_pool; ++ ++static void ++__page_pool_wake(struct blktap_page_pool *pool) ++{ ++ mempool_t *mem = pool->bufs; ++ ++ /* ++ NB. slightly wasteful to always wait for a full segment ++ set. but this ensures the next disk makes ++ progress. presently, the repeated request struct ++ alloc/release cycles would otherwise keep everyone spinning. ++ */ ++ ++ if (mem->curr_nr >= POOL_MAX_REQUEST_PAGES) ++ wake_up(&pool->wait); ++} ++ ++int ++blktap_request_get_pages(struct blktap *tap, ++ struct blktap_request *request, int nr_pages) ++{ ++ struct blktap_page_pool *pool = tap->pool; ++ mempool_t *mem = pool->bufs; ++ struct page *page; ++ ++ BUG_ON(request->nr_pages != 0); ++ BUG_ON(nr_pages > POOL_MAX_REQUEST_PAGES); ++ ++ if (mem->curr_nr < nr_pages) ++ return -ENOMEM; ++ ++ /* NB. avoid thundering herds of tapdisks colliding. */ ++ spin_lock(&pool->lock); ++ ++ if (mem->curr_nr < nr_pages) { ++ spin_unlock(&pool->lock); ++ return -ENOMEM; ++ } ++ ++ while (request->nr_pages < nr_pages) { ++ page = mempool_alloc(mem, GFP_NOWAIT); ++ BUG_ON(!page); ++ request->pages[request->nr_pages++] = page; ++ } ++ ++ spin_unlock(&pool->lock); ++ ++ return 0; ++} ++ ++static void ++blktap_request_put_pages(struct blktap *tap, ++ struct blktap_request *request) ++{ ++ struct blktap_page_pool *pool = tap->pool; ++ struct page *page; ++ ++ while (request->nr_pages) { ++ page = request->pages[--request->nr_pages]; ++ mempool_free(page, pool->bufs); ++ } ++} ++ ++size_t ++blktap_request_debug(struct blktap *tap, char *buf, size_t size) ++{ ++ struct blktap_page_pool *pool = tap->pool; ++ mempool_t *mem = pool->bufs; ++ char *s = buf, *end = buf + size; ++ ++ s += snprintf(buf, end - s, ++ "pool:%s pages:%d free:%d\n", ++ kobject_name(&pool->kobj), ++ mem->min_nr, mem->curr_nr); ++ ++ return s - buf; ++} ++ ++static void ++blktap_request_ctor(void *obj) ++{ ++ struct blktap_request *request = obj; ++ ++ memset(request, 0, sizeof(*request)); ++ sg_init_table(request->sg_table, ARRAY_SIZE(request->sg_table)); ++} ++ ++struct blktap_request* ++blktap_request_alloc(struct blktap *tap) ++{ ++ struct blktap_request *request; ++ ++ request = mempool_alloc(request_pool, GFP_NOWAIT); ++ if (request) { ++ blktap_request_ctor(request); ++ request->tap = tap; ++ } ++ ++ return request; ++} ++ ++void ++blktap_request_free(struct blktap *tap, ++ struct blktap_request *request) ++{ ++ blktap_request_put_pages(tap, request); ++ ++ mempool_free(request, request_pool); ++ ++ __page_pool_wake(tap->pool); ++} ++ ++void ++blktap_request_bounce(struct blktap *tap, ++ struct blktap_request *request, ++ int seg, int write) ++{ ++ struct scatterlist *sg = &request->sg_table[seg]; ++ void *s, *p; ++ ++ if (!sg || !request) ++ return; ++ ++ BUG_ON(seg >= request->nr_pages); ++ ++ s = sg_virt(sg); ++ p = page_address(request->pages[seg]); ++ if (!s || !p) ++ return; ++ ++ p = (uint8_t*)p + sg->offset; ++ if (write) ++ memcpy(p, s, sg->length); ++ else ++ memcpy(s, p, sg->length); ++} ++ ++static int ++blktap_page_pool_resize(struct blktap_page_pool *pool, int target) ++{ ++ mempool_t *bufs = pool->bufs; ++ int err; ++ ++ /* NB. mempool asserts min_nr >= 1 */ ++ target = max(1, target); ++ ++ err = mempool_resize(bufs, target); ++ if (err) ++ return err; ++ ++ __page_pool_wake(pool); ++ ++ return 0; ++} ++ ++struct pool_attribute { ++ struct attribute attr; ++ ++ ssize_t (*show)(struct blktap_page_pool *pool, ++ char *buf); ++ ++ ssize_t (*store)(struct blktap_page_pool *pool, ++ const char *buf, size_t count); ++}; ++ ++#define kattr_to_pool_attr(_kattr) \ ++ container_of(_kattr, struct pool_attribute, attr) ++ ++static ssize_t ++blktap_page_pool_show_size(struct blktap_page_pool *pool, ++ char *buf) ++{ ++ mempool_t *mem = pool->bufs; ++ return sprintf(buf, "%d", mem->min_nr); ++} ++ ++static ssize_t ++blktap_page_pool_store_size(struct blktap_page_pool *pool, ++ const char *buf, size_t size) ++{ ++ int target; ++ ++ /* ++ * NB. target fixup to avoid undesired results. less than a ++ * full segment set can wedge the disk. much more than a ++ * couple times the physical queue depth is rarely useful. ++ */ ++ ++ target = simple_strtoul(buf, NULL, 0); ++ target = max(POOL_MAX_REQUEST_PAGES, target); ++ target = min(target, POOL_MAX_PAGES); ++ ++ return blktap_page_pool_resize(pool, target) ? : size; ++} ++ ++static struct pool_attribute blktap_page_pool_attr_size = ++ __ATTR(size, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, ++ blktap_page_pool_show_size, ++ blktap_page_pool_store_size); ++ ++static ssize_t ++blktap_page_pool_show_free(struct blktap_page_pool *pool, ++ char *buf) ++{ ++ mempool_t *mem = pool->bufs; ++ return sprintf(buf, "%d", mem->curr_nr); ++} ++ ++static struct pool_attribute blktap_page_pool_attr_free = ++ __ATTR(free, S_IRUSR|S_IRGRP|S_IROTH, ++ blktap_page_pool_show_free, ++ NULL); ++ ++static struct attribute *blktap_page_pool_attrs[] = { ++ &blktap_page_pool_attr_size.attr, ++ &blktap_page_pool_attr_free.attr, ++ NULL, ++}; ++ ++static inline struct kobject* ++__blktap_kset_find_obj(struct kset *kset, const char *name) ++{ ++ struct kobject *k; ++ struct kobject *ret = NULL; ++ ++ spin_lock(&kset->list_lock); ++ list_for_each_entry(k, &kset->list, entry) { ++ if (kobject_name(k) && !strcmp(kobject_name(k), name)) { ++ ret = kobject_get(k); ++ break; ++ } ++ } ++ spin_unlock(&kset->list_lock); ++ return ret; ++} ++ ++static ssize_t ++blktap_page_pool_show_attr(struct kobject *kobj, struct attribute *kattr, ++ char *buf) ++{ ++ struct blktap_page_pool *pool = kobj_to_pool(kobj); ++ struct pool_attribute *attr = kattr_to_pool_attr(kattr); ++ ++ if (attr->show) ++ return attr->show(pool, buf); ++ ++ return -EIO; ++} ++ ++static ssize_t ++blktap_page_pool_store_attr(struct kobject *kobj, struct attribute *kattr, ++ const char *buf, size_t size) ++{ ++ struct blktap_page_pool *pool = kobj_to_pool(kobj); ++ struct pool_attribute *attr = kattr_to_pool_attr(kattr); ++ ++ if (attr->show) ++ return attr->store(pool, buf, size); ++ ++ return -EIO; ++} ++ ++static struct sysfs_ops blktap_page_pool_sysfs_ops = { ++ .show = blktap_page_pool_show_attr, ++ .store = blktap_page_pool_store_attr, ++}; ++ ++static void ++blktap_page_pool_release(struct kobject *kobj) ++{ ++ struct blktap_page_pool *pool = kobj_to_pool(kobj); ++ mempool_destroy(pool->bufs); ++ kfree(pool); ++} ++ ++struct kobj_type blktap_page_pool_ktype = { ++ .release = blktap_page_pool_release, ++ .sysfs_ops = &blktap_page_pool_sysfs_ops, ++ .default_attrs = blktap_page_pool_attrs, ++}; ++ ++static void* ++__mempool_page_alloc(gfp_t gfp_mask, void *pool_data) ++{ ++ struct page *page; ++ ++ if (!gfpflags_allow_blocking(gfp_mask)) ++ return NULL; ++ ++ page = alloc_page(gfp_mask); ++ if (page) ++ SetPageReserved(page); ++ ++ return page; ++} ++ ++static void ++__mempool_page_free(void *element, void *pool_data) ++{ ++ struct page *page = element; ++ ++ ClearPageReserved(page); ++ put_page(page); ++} ++ ++static struct kobject* ++blktap_page_pool_create(const char *name, int nr_pages) ++{ ++ struct blktap_page_pool *pool; ++ int err; ++ ++ pool = kzalloc(sizeof(*pool), GFP_KERNEL); ++ if (!pool) ++ goto fail; ++ ++ spin_lock_init(&pool->lock); ++ init_waitqueue_head(&pool->wait); ++ ++ pool->bufs = mempool_create(nr_pages, ++ __mempool_page_alloc, __mempool_page_free, ++ pool); ++ if (!pool->bufs) ++ goto fail_pool; ++ ++ kobject_init(&pool->kobj, &blktap_page_pool_ktype); ++ pool->kobj.kset = pool_set; ++ err = kobject_add(&pool->kobj, &pool_set->kobj, "%s", name); ++ if (err) ++ goto fail_bufs; ++ ++ return &pool->kobj; ++ ++ kobject_del(&pool->kobj); ++fail_bufs: ++ mempool_destroy(pool->bufs); ++fail_pool: ++ kfree(pool); ++fail: ++ return NULL; ++} ++ ++struct blktap_page_pool* ++blktap_page_pool_get(const char *name) ++{ ++ struct kobject *kobj; ++ ++ kobj = __blktap_kset_find_obj(pool_set, name); ++ if (!kobj) ++ kobj = blktap_page_pool_create(name, ++ POOL_DEFAULT_PAGES); ++ if (!kobj) ++ return ERR_PTR(-ENOMEM); ++ ++ return kobj_to_pool(kobj); ++} ++ ++int __init ++blktap_page_pool_init(struct kobject *parent) ++{ ++ request_cache = ++ kmem_cache_create("blktap-request", ++ sizeof(struct blktap_request), 0, ++ 0, NULL); ++ if (!request_cache) ++ return -ENOMEM; ++ ++ request_pool = ++ mempool_create_slab_pool(POOL_MIN_REQS, request_cache); ++ if (!request_pool) ++ return -ENOMEM; ++ ++ pool_set = kset_create_and_add("pools", NULL, parent); ++ if (!pool_set) ++ return -ENOMEM; ++ ++ return 0; ++} ++ ++void ++blktap_page_pool_exit(void) ++{ ++ if (pool_set) { ++ BUG_ON(!list_empty(&pool_set->list)); ++ kset_unregister(pool_set); ++ pool_set = NULL; ++ } ++ ++ if (request_pool) { ++ mempool_destroy(request_pool); ++ request_pool = NULL; ++ } ++ ++ if (request_cache) { ++ kmem_cache_destroy(request_cache); ++ request_cache = NULL; ++ } ++} +--- /dev/null ++++ b/drivers/block/blktap/ring.c +@@ -0,0 +1,814 @@ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "blktap.h" ++ ++#define BLKTAP_DESTROY_RETRY_PERIOD (HZ/10) /*100 msec*/ ++ ++int blktap_ring_major; ++static struct cdev blktap_ring_cdev; ++ ++ /* ++ * BLKTAP - immediately before the mmap area, ++ * we have a bunch of pages reserved for shared memory rings. ++ */ ++#define RING_PAGES 1 ++ ++#define BLKTAP_INFO_SIZE_AT(_memb) \ ++ offsetof(struct blktap_device_info, _memb) + \ ++ sizeof(((struct blktap_device_info*)0)->_memb) ++ ++static void ++blktap_ring_read_response(struct blktap *tap, ++ const struct blktap_ring_response *rsp) ++{ ++ struct blktap_ring *ring = &tap->ring; ++ struct blktap_request *request; ++ int usr_idx, err; ++ ++ request = NULL; ++ ++ usr_idx = rsp->id; ++ if (usr_idx < 0 || usr_idx >= BLKTAP_RING_SIZE) { ++ err = -ERANGE; ++ goto invalid; ++ } ++ ++ request = ring->pending[usr_idx]; ++ ++ if (!request) { ++ err = -ESRCH; ++ goto invalid; ++ } ++ ++ if (rsp->operation != request->operation) { ++ err = -EINVAL; ++ goto invalid; ++ } ++ ++ dev_dbg(ring->dev, ++ "request %d [%p] response: %d\n", ++ request->usr_idx, request, rsp->status); ++ ++ err = rsp->status == BLKTAP_RSP_OKAY ? BLK_STS_OK : BLK_STS_IOERR; ++end_request: ++ blktap_device_end_request(tap, request, err); ++ return; ++ ++invalid: ++ dev_warn(ring->dev, ++ "invalid response, idx:%d status:%d op:%d/%d: err %d\n", ++ usr_idx, rsp->status, ++ rsp->operation, request->operation, ++ err); ++ if (request) ++ goto end_request; ++} ++ ++static void ++blktap_read_ring(struct blktap *tap) ++{ ++ struct blktap_ring *ring = &tap->ring; ++ struct blktap_ring_response rsp; ++ RING_IDX rc, rp; ++ ++ if (!ring->vma) { ++ return; ++ } ++ ++ /* for each outstanding message on the ring */ ++ rp = ring->ring.sring->rsp_prod; ++ rmb(); ++ ++ for (rc = ring->ring.rsp_cons; rc != rp; rc++) { ++ memcpy(&rsp, RING_GET_RESPONSE(&ring->ring, rc), sizeof(rsp)); ++ blktap_ring_read_response(tap, &rsp); ++ } ++ ++ ring->ring.rsp_cons = rc; ++ ++ blktap_device_run_queues(tap); ++} ++ ++#define MMAP_VADDR(_start, _req, _seg) \ ++ ((_start) + \ ++ ((_req) * BLKTAP_SEGMENT_MAX * BLKTAP_PAGE_SIZE) + \ ++ ((_seg) * BLKTAP_PAGE_SIZE)) ++ ++static vm_fault_t blktap_ring_fault(struct vm_fault *vmf) ++{ ++ return VM_FAULT_SIGBUS; ++} ++ ++static void ++blktap_ring_fail_pending(struct blktap *tap) ++{ ++ struct blktap_ring *ring = &tap->ring; ++ struct blktap_request *request; ++ int usr_idx; ++ ++ for (usr_idx = 0; usr_idx < BLKTAP_RING_SIZE; usr_idx++) { ++ request = ring->pending[usr_idx]; ++ if (!request) ++ continue; ++ ++ request->rq->cmd_flags |= RQF_QUIET; ++ blktap_device_end_request(tap, request, BLK_STS_IOERR); ++ } ++} ++ ++static void ++blktap_ring_vm_close(struct vm_area_struct *vma) ++{ ++ struct blktap *tap = vma->vm_private_data; ++ struct blktap_ring *ring = &tap->ring; ++ struct page *page = virt_to_page(ring->ring.sring); ++ ++ blktap_ring_fail_pending(tap); ++ ++ zap_page_range(vma, vma->vm_start, PAGE_SIZE); ++ ClearPageReserved(page); ++ __free_page(page); ++ ++ ring->vma = NULL; ++ wake_up_interruptible(&tap->remove_wait); ++ ++ if (test_bit(BLKTAP_SHUTDOWN_REQUESTED, &tap->dev_inuse)) ++ blktap_control_destroy_tap(tap); ++} ++ ++static struct vm_operations_struct blktap_ring_vm_operations = { ++ .close = blktap_ring_vm_close, ++ .fault = blktap_ring_fault, ++}; ++ ++int ++blktap_ring_map_segment(struct blktap *tap, ++ struct blktap_request *request, ++ int seg) ++{ ++ struct blktap_ring *ring = &tap->ring; ++ unsigned long uaddr; ++ int ret; ++ ++ down_write(&ring->vma->vm_mm->mmap_sem); ++ ++ uaddr = MMAP_VADDR(ring->user_vstart, request->usr_idx, seg); ++ ret = vm_insert_page(ring->vma, uaddr, request->pages[seg]); ++ ++ up_write(&ring->vma->vm_mm->mmap_sem); ++ ++ return ret; ++} ++ ++int ++blktap_ring_map_request(struct blktap *tap, ++ struct blktap_request *request) ++{ ++ int seg, err = 0; ++ int write; ++ ++ write = request->operation == BLKTAP_OP_WRITE; ++ ++ for (seg = 0; seg < request->nr_pages; seg++) { ++ if (write) ++ blktap_request_bounce(tap, request, seg, write); ++ ++ err = blktap_ring_map_segment(tap, request, seg); ++ if (err) ++ break; ++ } ++ ++ if (err) ++ blktap_ring_unmap_request(tap, request); ++ ++ return err; ++} ++ ++void ++blktap_ring_unmap_request(struct blktap *tap, ++ struct blktap_request *request) ++{ ++ struct blktap_ring *ring = &tap->ring; ++ unsigned long uaddr; ++ unsigned size; ++ int seg, read; ++ ++ uaddr = MMAP_VADDR(ring->user_vstart, request->usr_idx, 0); ++ size = request->nr_pages << PAGE_SHIFT; ++ read = request->operation == BLKTAP_OP_READ; ++ ++ if (read) ++ for (seg = 0; seg < request->nr_pages; seg++) ++ blktap_request_bounce(tap, request, seg, !read); ++ ++ zap_page_range(ring->vma, uaddr, size); ++} ++ ++void ++blktap_ring_free_request(struct blktap *tap, ++ struct blktap_request *request) ++{ ++ struct blktap_ring *ring = &tap->ring; ++ ++ ring->pending[request->usr_idx] = NULL; ++ atomic_dec(&ring->n_pending); ++ wake_up_interruptible(&tap->remove_wait); ++ ++ blktap_request_free(tap, request); ++} ++ ++struct blktap_request* ++blktap_ring_make_request(struct blktap *tap) ++{ ++ struct blktap_ring *ring = &tap->ring; ++ struct blktap_request *request; ++ int usr_idx; ++ ++ if (RING_FULL(&ring->ring)) ++ return ERR_PTR(-ENOSPC); ++ ++ request = blktap_request_alloc(tap); ++ if (!request) ++ return ERR_PTR(-ENOMEM); ++ ++ for (usr_idx = 0; usr_idx < BLKTAP_RING_SIZE; usr_idx++) ++ if (!ring->pending[usr_idx]) ++ break; ++ ++ BUG_ON(usr_idx >= BLKTAP_RING_SIZE); ++ ++ request->tap = tap; ++ request->usr_idx = usr_idx; ++ ++ ring->pending[usr_idx] = request; ++ atomic_inc(&ring->n_pending); ++ wake_up_interruptible(&tap->remove_wait); ++ ++ return request; ++} ++ ++static int ++blktap_ring_make_rw_request(struct blktap *tap, ++ struct blktap_request *request, ++ struct blktap_ring_request *breq) ++{ ++ struct scatterlist *sg; ++ unsigned int i, nsecs = 0; ++ ++ blktap_for_each_sg(sg, request, i) { ++ struct blktap_segment *seg = &breq->u.rw.seg[i]; ++ int first, count; ++ ++ count = sg->length >> 9; ++ first = sg->offset >> 9; ++ ++ seg->first_sect = first; ++ seg->last_sect = first + count - 1; ++ ++ nsecs += count; ++ } ++ ++ breq->u.rw.sector_number = blk_rq_pos(request->rq); ++ ++ return nsecs; ++} ++ ++static int ++blktap_ring_make_tr_request(struct blktap *tap, ++ struct blktap_request *request, ++ struct blktap_ring_request *breq) ++{ ++ struct bio *bio = request->rq->bio; ++ unsigned int nsecs; ++ ++ breq->u.tr.nr_sectors = nsecs = bio_sectors(bio); ++ breq->u.tr.sector_number = bio->bi_iter.bi_sector; ++ ++ return nsecs; ++} ++ ++void ++blktap_ring_submit_request(struct blktap *tap, ++ struct blktap_request *request) ++{ ++ struct blktap_ring *ring = &tap->ring; ++ struct blktap_ring_request *breq; ++ int nsecs; ++ ++ dev_dbg(ring->dev, ++ "request %d [%p] submit\n", request->usr_idx, request); ++ ++ breq = RING_GET_REQUEST(&ring->ring, ring->ring.req_prod_pvt); ++ ++ breq->id = request->usr_idx; ++ breq->__pad = 0; ++ breq->operation = request->operation; ++ breq->nr_segments = request->nr_pages; ++ ++ switch (breq->operation) { ++ case BLKTAP_OP_READ: ++ nsecs = blktap_ring_make_rw_request(tap, request, breq); ++ ++ tap->stats.st_rd_sect += nsecs; ++ tap->stats.st_rd_req++; ++ break; ++ ++ case BLKTAP_OP_WRITE: ++ nsecs = blktap_ring_make_rw_request(tap, request, breq); ++ ++ tap->stats.st_wr_sect += nsecs; ++ tap->stats.st_wr_req++; ++ break; ++ ++ case BLKTAP_OP_FLUSH: ++ breq->u.rw.sector_number = 0; ++ tap->stats.st_fl_req++; ++ break; ++ ++ case BLKTAP_OP_TRIM: ++ nsecs = blktap_ring_make_tr_request(tap, request, breq); ++ ++ tap->stats.st_tr_sect += nsecs; ++ tap->stats.st_tr_req++; ++ break; ++ default: ++ BUG(); ++ } ++ ++ ring->ring.req_prod_pvt++; ++} ++ ++static int ++blktap_ring_open(struct inode *inode, struct file *filp) ++{ ++ struct blktap *tap = NULL; ++ int minor; ++ ++ minor = iminor(inode); ++ ++ if (minor < blktap_max_minor) ++ tap = blktaps[minor]; ++ ++ if (!tap) ++ return -ENXIO; ++ ++ if (test_bit(BLKTAP_SHUTDOWN_REQUESTED, &tap->dev_inuse)) ++ return -ENXIO; ++ ++ if (tap->ring.task) ++ return -EBUSY; ++ ++ filp->private_data = tap; ++ tap->ring.task = current; ++ ++ return 0; ++} ++ ++static void ++blktap_destroy_work(struct work_struct *work) ++{ ++ struct blktap *tap ++ = container_of(work, struct blktap, destroy_work.work); ++ ++ if (blktap_device_try_destroy(tap)) { ++ schedule_delayed_work(&tap->destroy_work, BLKTAP_DESTROY_RETRY_PERIOD); ++ } ++} ++ ++static int ++blktap_ring_release(struct inode *inode, struct file *filp) ++{ ++ struct blktap *tap = filp->private_data; ++ ++ tap->ring.task = NULL; ++ ++ if (blktap_device_try_destroy(tap)) { ++ INIT_DELAYED_WORK(&tap->destroy_work, blktap_destroy_work); ++ schedule_delayed_work(&tap->destroy_work, BLKTAP_DESTROY_RETRY_PERIOD); ++ } ++ ++ return 0; ++} ++ ++static int ++blktap_ring_mmap(struct file *filp, struct vm_area_struct *vma) ++{ ++ struct blktap *tap = filp->private_data; ++ struct blktap_ring *ring = &tap->ring; ++ struct blktap_sring *sring; ++ struct page *page = NULL; ++ int err; ++ ++ if (ring->vma) ++ return -EBUSY; ++ ++ page = alloc_page(GFP_KERNEL|__GFP_ZERO); ++ if (!page) ++ return -ENOMEM; ++ ++ SetPageReserved(page); ++ ++ err = vm_insert_page(vma, vma->vm_start, page); ++ if (err) ++ goto fail; ++ ++ sring = page_address(page); ++ SHARED_RING_INIT(sring); ++ FRONT_RING_INIT(&ring->ring, sring, PAGE_SIZE); ++ ++ ring->ring_vstart = vma->vm_start; ++ ring->user_vstart = ring->ring_vstart + PAGE_SIZE; ++ ++ vma->vm_private_data = tap; ++ ++ vma->vm_flags |= VM_DONTCOPY; ++ vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; ++ ++ vma->vm_ops = &blktap_ring_vm_operations; ++ ++ ring->vma = vma; ++ wake_up_interruptible(&tap->remove_wait); ++ ++ return 0; ++ ++fail: ++ if (page) { ++ zap_page_range(vma, vma->vm_start, PAGE_SIZE); ++ ClearPageReserved(page); ++ __free_page(page); ++ } ++ ++ return err; ++} ++ ++static inline void ++blktap_ring_set_message(struct blktap *tap, int msg) ++{ ++ struct blktap_ring *ring = &tap->ring; ++ ++ if (ring->ring.sring) ++ ring->ring.sring->pad[0] = msg; ++} ++ ++static long ++blktap_ring_ioctl(struct file *filp, ++ unsigned int cmd, unsigned long arg) ++{ ++ struct blktap *tap = filp->private_data; ++ struct blktap_ring *ring = &tap->ring; ++ void __user *ptr = (void *)arg; ++ int err; ++ ++ BTDBG("%d: cmd: %u, arg: %lu\n", tap->minor, cmd, arg); ++ ++ if (!ring->vma || ring->vma->vm_mm != current->mm) ++ return -EACCES; ++ ++ switch(cmd) { ++ case BLKTAP_IOCTL_RESPOND: ++ ++ blktap_read_ring(tap); ++ return 0; ++ ++ case BLKTAP_IOCTL_CREATE_DEVICE_COMPAT: { ++ struct blktap_device_info info; ++ struct blktap2_params params; ++ ++ if (copy_from_user(¶ms, ptr, sizeof(params))) ++ return -EFAULT; ++ ++ info.capacity = params.capacity; ++ info.sector_size = params.sector_size; ++ info.flags = 0; ++ ++ err = blktap_device_create(tap, &info); ++ if (err) ++ return err; ++ ++ if (params.name[0]) { ++ strncpy(tap->name, params.name, sizeof(params.name)); ++ tap->name[sizeof(tap->name)-1] = 0; ++ } ++ ++ return 0; ++ } ++ ++ case BLKTAP_IOCTL_CREATE_DEVICE: { ++ struct blktap_device_info __user *ptr = (void *)arg; ++ struct blktap_device_info info; ++ unsigned long mask; ++ size_t base_sz, sz; ++ ++ mask = BLKTAP_DEVICE_FLAG_RO; ++ mask |= BLKTAP_DEVICE_FLAG_PSZ; ++ mask |= BLKTAP_DEVICE_FLAG_FLUSH; ++ mask |= BLKTAP_DEVICE_FLAG_TRIM; ++ ++ memset(&info, 0, sizeof(info)); ++ sz = base_sz = BLKTAP_INFO_SIZE_AT(flags); ++ ++ if (copy_from_user(&info, ptr, sz)) ++ return -EFAULT; ++ ++ if ((info.flags & BLKTAP_DEVICE_FLAG_PSZ) != 0) ++ sz = BLKTAP_INFO_SIZE_AT(phys_block_offset); ++ ++ if (info.flags & BLKTAP_DEVICE_FLAG_TRIM) ++ sz = BLKTAP_INFO_SIZE_AT(trim_block_offset); ++ ++ if (sz > base_sz) ++ if (copy_from_user(&info, ptr, sz)) ++ return -EFAULT; ++ ++ if (put_user(info.flags & mask, &ptr->flags)) ++ return -EFAULT; ++ ++ return blktap_device_create(tap, &info); ++ } ++ ++ case BLKTAP_IOCTL_REMOVE_DEVICE: ++ ++ return blktap_device_destroy(tap); ++ ++ case BLKTAP2_IOCTL_SET_PARAMS: { ++ struct blktap2_params params; ++ struct blktap_device_info info; ++ ++ if (!arg) ++ return -EINVAL; ++ ++ if (!test_bit(BLKTAP_PAUSED, &tap->dev_inuse)) ++ return -EINVAL; ++ ++ if (copy_from_user(¶ms, (struct blktap_params __user *)arg, ++ sizeof(params))) { ++ BTERR("failed to get params\n"); ++ return -EFAULT; ++ } ++ ++ info.capacity = params.capacity; ++ info.sector_size = params.sector_size; ++ info.flags = 0; ++ ++ blktap_device_configure(tap, &info); ++ ++ if (params.name[0]) { ++ strncpy(tap->name, params.name, sizeof(params.name)); ++ tap->name[sizeof(tap->name)-1] = 0; ++ } ++ ++ return 0; ++ } ++ ++ case BLKTAP2_IOCTL_PAUSE: ++ if (!test_bit(BLKTAP_PAUSE_REQUESTED, &tap->dev_inuse)) ++ return -EINVAL; ++ ++ set_bit(BLKTAP_PAUSED, &tap->dev_inuse); ++ clear_bit(BLKTAP_PAUSE_REQUESTED, &tap->dev_inuse); ++ ++ blktap_ring_set_message(tap, 0); ++ wake_up_interruptible(&tap->remove_wait); ++ ++ return 0; ++ ++ case BLKTAP2_IOCTL_REOPEN: ++ if (!test_bit(BLKTAP_PAUSED, &tap->dev_inuse)) ++ return -EINVAL; ++ ++ if (!arg) ++ return -EINVAL; ++ ++ if (copy_to_user((char __user *)arg, ++ tap->name, ++ strlen(tap->name) + 1)) ++ return -EFAULT; ++ ++ blktap_ring_set_message(tap, 0); ++ wake_up_interruptible(&tap->remove_wait); ++ ++ return 0; ++ ++ case BLKTAP2_IOCTL_RESUME: ++ if (!test_bit(BLKTAP_PAUSED, &tap->dev_inuse)) ++ return -EINVAL; ++ ++ tap->ring.response = (int)arg; ++ if (!tap->ring.response) ++ clear_bit(BLKTAP_PAUSED, &tap->dev_inuse); ++ ++ blktap_ring_set_message(tap, 0); ++ wake_up_interruptible(&tap->remove_wait); ++ ++ return 0; ++ } ++ ++ return -ENOTTY; ++} ++ ++static unsigned int blktap_ring_poll(struct file *filp, poll_table *wait) ++{ ++ struct blktap *tap = filp->private_data; ++ struct blktap_ring *ring = &tap->ring; ++ struct blktap_device *tapdev = &tap->device; ++ int work; ++ ++ poll_wait(filp, &tap->pool->wait, wait); ++ poll_wait(filp, &ring->poll_wait, wait); ++ ++ mutex_lock(&tapdev->lock); ++ if (ring->vma) ++ blktap_device_run_queues(tap); ++ ++ work = ring->ring.sring->rsp_prod != ring->ring.sring->req_prod; ++ mutex_unlock(&tapdev->lock); ++ ++ if (work || ++ *BLKTAP_RING_MESSAGE(ring->ring.sring) || ++ test_and_clear_bit(BLKTAP_DEVICE_CLOSED, &tap->dev_inuse)) ++ return POLLIN | POLLRDNORM; ++ ++ return 0; ++} ++ ++static struct file_operations blktap_ring_file_operations = { ++ .owner = THIS_MODULE, ++ .open = blktap_ring_open, ++ .release = blktap_ring_release, ++ .unlocked_ioctl = blktap_ring_ioctl, ++ .mmap = blktap_ring_mmap, ++ .poll = blktap_ring_poll, ++}; ++ ++void ++blktap_ring_kick_user(struct blktap *tap) ++{ ++ wake_up(&tap->ring.poll_wait); ++} ++ ++int ++blktap_ring_resume(struct blktap *tap) ++{ ++ int err; ++ struct blktap_ring *ring = &tap->ring; ++ ++ if (!test_bit(BLKTAP_PAUSED, &tap->dev_inuse)) ++ return -EINVAL; ++ ++ /* set shared flag for resume */ ++ ring->response = 0; ++ ++ blktap_ring_set_message(tap, BLKTAP2_RING_MESSAGE_RESUME); ++ blktap_ring_kick_user(tap); ++ ++ wait_event_interruptible(tap->remove_wait, ring->response || ++ !test_bit(BLKTAP_PAUSED, &tap->dev_inuse)); ++ ++ err = ring->response; ++ ring->response = 0; ++ ++ BTDBG("err: %d\n", err); ++ ++ if (err) ++ return err; ++ ++ if (test_bit(BLKTAP_PAUSED, &tap->dev_inuse)) ++ return -EAGAIN; ++ ++ return 0; ++} ++ ++int ++blktap_ring_pause(struct blktap *tap) ++{ ++ struct blktap_ring *ring = &tap->ring; ++ ++ if (!test_bit(BLKTAP_PAUSE_REQUESTED, &tap->dev_inuse)) ++ return -EINVAL; ++ ++ BTDBG("draining queue\n"); ++ for (;;) { ++ int r; ++ ++ r = wait_event_interruptible_timeout(tap->remove_wait, ++ atomic_read(&ring->n_pending) == 0, ++ HZ / 10); ++ if (r == -ERESTARTSYS) ++ return -EAGAIN; ++ if (r > 0) ++ break; ++ } ++ ++ blktap_ring_set_message(tap, BLKTAP2_RING_MESSAGE_PAUSE); ++ blktap_ring_kick_user(tap); ++ ++ BTDBG("waiting for tapdisk response\n"); ++ wait_event_interruptible(tap->remove_wait, test_bit(BLKTAP_PAUSED, &tap->dev_inuse)); ++ if (!test_bit(BLKTAP_PAUSED, &tap->dev_inuse)) ++ return -EAGAIN; ++ ++ return 0; ++} ++ ++int ++blktap_ring_destroy(struct blktap *tap) ++{ ++ struct blktap_ring *ring = &tap->ring; ++ ++ if (ring->task || ring->vma || test_bit(BLKTAP_DEVICE, &tap->dev_inuse)) ++ return -EBUSY; ++ ++ return 0; ++} ++ ++int ++blktap_ring_create(struct blktap *tap) ++{ ++ struct blktap_ring *ring = &tap->ring; ++ ++ init_waitqueue_head(&ring->poll_wait); ++ ring->devno = MKDEV(blktap_ring_major, tap->minor); ++ ++ return 0; ++} ++ ++size_t ++blktap_ring_debug(struct blktap *tap, char *buf, size_t size) ++{ ++ struct blktap_ring *ring = &tap->ring; ++ char *s = buf, *end = buf + size; ++ int usr_idx; ++ ++ s += snprintf(s, end - s, ++ "begin pending:%d\n", atomic_read(&ring->n_pending)); ++ ++ for (usr_idx = 0; usr_idx < BLKTAP_RING_SIZE; usr_idx++) { ++ struct blktap_request *request; ++ struct timeval t; ++ ++ request = ring->pending[usr_idx]; ++ if (!request) ++ continue; ++ ++ jiffies_to_timeval(jiffies, &t); ++ ++ s += snprintf(s, end - s, ++ "%02d: usr_idx:%02d " ++ "op:%x nr_pages:%02d time:%lu.%09lu\n", ++ usr_idx, request->usr_idx, ++ request->operation, request->nr_pages, ++ t.tv_sec, t.tv_usec); ++ } ++ ++ s += snprintf(s, end - s, "end pending\n"); ++ ++ return s - buf; ++} ++ ++ ++int __init ++blktap_ring_init(void) ++{ ++ dev_t dev = 0; ++ int err; ++ ++ cdev_init(&blktap_ring_cdev, &blktap_ring_file_operations); ++ blktap_ring_cdev.owner = THIS_MODULE; ++ ++ err = alloc_chrdev_region(&dev, 0, MAX_BLKTAP_DEVICE, "blktap2"); ++ if (err < 0) { ++ BTERR("error registering ring devices: %d\n", err); ++ return err; ++ } ++ ++ err = cdev_add(&blktap_ring_cdev, dev, MAX_BLKTAP_DEVICE); ++ if (err) { ++ BTERR("error adding ring device: %d\n", err); ++ unregister_chrdev_region(dev, MAX_BLKTAP_DEVICE); ++ return err; ++ } ++ ++ blktap_ring_major = MAJOR(dev); ++ BTINFO("blktap ring major: %d\n", blktap_ring_major); ++ ++ return 0; ++} ++ ++void ++blktap_ring_exit(void) ++{ ++ if (!blktap_ring_major) ++ return; ++ ++ cdev_del(&blktap_ring_cdev); ++ unregister_chrdev_region(MKDEV(blktap_ring_major, 0), ++ MAX_BLKTAP_DEVICE); ++ ++ blktap_ring_major = 0; ++} +--- /dev/null ++++ b/drivers/block/blktap/sysfs.c +@@ -0,0 +1,359 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "blktap.h" ++ ++int blktap_debug_level = 1; ++ ++static struct class *class; ++ ++static ssize_t ++blktap_sysfs_set_name(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) ++{ ++ struct blktap *tap; ++ ++ tap = dev_get_drvdata(dev); ++ if (!tap) ++ return 0; ++ ++ if (size >= BLKTAP_NAME_MAX) ++ return -ENAMETOOLONG; ++ ++ if (strnlen(buf, size) != size) ++ return -EINVAL; ++ ++ strcpy(tap->name, buf); ++ ++ return size; ++} ++ ++static ssize_t ++blktap_sysfs_get_name(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct blktap *tap; ++ ssize_t size; ++ ++ tap = dev_get_drvdata(dev); ++ if (!tap) ++ return 0; ++ ++ if (tap->name[0]) ++ size = sprintf(buf, "%s\n", tap->name); ++ else ++ size = sprintf(buf, "%d\n", tap->minor); ++ ++ return size; ++} ++static DEVICE_ATTR(name, S_IRUGO|S_IWUSR, ++ blktap_sysfs_get_name, blktap_sysfs_set_name); ++ ++static void ++blktap_sysfs_remove_work(struct work_struct *work) ++{ ++ struct blktap *tap ++ = container_of(work, struct blktap, remove_work); ++ blktap_control_destroy_tap(tap); ++} ++ ++static ssize_t ++blktap_sysfs_remove_device(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t size) ++{ ++ struct blktap *tap; ++ int err; ++ ++ tap = dev_get_drvdata(dev); ++ if (!tap) ++ return size; ++ ++ if (test_and_set_bit(BLKTAP_SHUTDOWN_REQUESTED, &tap->dev_inuse)) ++ goto wait; ++ ++ if (tap->ring.vma) { ++ struct blktap_sring *sring = tap->ring.ring.sring; ++ *BLKTAP_RING_MESSAGE(sring) = BLKTAP_RING_MESSAGE_CLOSE; ++ blktap_ring_kick_user(tap); ++ } else { ++ INIT_WORK(&tap->remove_work, blktap_sysfs_remove_work); ++ schedule_work(&tap->remove_work); ++ } ++wait: ++ err = wait_event_interruptible(tap->remove_wait, ++ !dev_get_drvdata(dev)); ++ if (err) ++ return err; ++ ++ return size; ++} ++static DEVICE_ATTR(remove, S_IWUSR, NULL, blktap_sysfs_remove_device); ++ ++static ssize_t ++blktap_sysfs_pause_device(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t size) ++{ ++ int err; ++ struct blktap *tap = dev_get_drvdata(dev); ++ ++ BTDBG("pausing %u:%u: dev_inuse: %lu\n", ++ MAJOR(tap->ring.devno), MINOR(tap->ring.devno), tap->dev_inuse); ++ ++ if (!tap->ring.dev || ++ test_bit(BLKTAP_SHUTDOWN_REQUESTED, &tap->dev_inuse)) { ++ err = -ENODEV; ++ goto out; ++ } ++ ++ if (test_bit(BLKTAP_PAUSE_REQUESTED, &tap->dev_inuse)) { ++ err = -EBUSY; ++ goto out; ++ } ++ ++ if (test_bit(BLKTAP_PAUSED, &tap->dev_inuse)) { ++ err = 0; ++ goto out; ++ } ++ ++ err = blktap_device_pause(tap); ++ ++out: ++ ++ return (err ? err : size); ++} ++static DEVICE_ATTR(pause, S_IWUSR, NULL, blktap_sysfs_pause_device); ++ ++static ssize_t ++blktap_sysfs_resume_device(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t size) ++{ ++ int err; ++ struct blktap *tap = dev_get_drvdata(dev); ++ ++ if (!tap->ring.dev || ++ test_bit(BLKTAP_SHUTDOWN_REQUESTED, &tap->dev_inuse)) { ++ err = -ENODEV; ++ goto out; ++ } ++ ++ if (!test_bit(BLKTAP_PAUSED, &tap->dev_inuse)) { ++ err = -EINVAL; ++ goto out; ++ } ++ ++ err = blktap_device_resume(tap); ++ ++out: ++ ++ BTDBG("returning %d\n", (err ? err : (int)size)); ++ return (err ? err : size); ++} ++static DEVICE_ATTR(resume, S_IWUSR, NULL, blktap_sysfs_resume_device); ++ ++static ssize_t ++blktap_sysfs_debug_device(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct blktap *tap; ++ char *s = buf, *end = buf + PAGE_SIZE; ++ ++ tap = dev_get_drvdata(dev); ++ if (!tap) ++ return 0; ++ ++ s += blktap_control_debug(tap, s, end - s); ++ ++ s += blktap_request_debug(tap, s, end - s); ++ ++ s += blktap_device_debug(tap, s, end - s); ++ ++ s += blktap_ring_debug(tap, s, end - s); ++ ++ return s - buf; ++} ++static DEVICE_ATTR(debug, S_IRUGO, blktap_sysfs_debug_device, NULL); ++ ++static ssize_t ++blktap_sysfs_show_task(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct blktap *tap; ++ ssize_t rv = 0; ++ ++ tap = dev_get_drvdata(dev); ++ if (!tap) ++ return 0; ++ ++ if (tap->ring.task) ++ rv = sprintf(buf, "%d\n", tap->ring.task->pid); ++ ++ return rv; ++} ++static DEVICE_ATTR(task, S_IRUGO, blktap_sysfs_show_task, NULL); ++ ++static ssize_t ++blktap_sysfs_show_pool(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct blktap *tap = dev_get_drvdata(dev); ++ return sprintf(buf, "%s", kobject_name(&tap->pool->kobj)); ++} ++ ++static ssize_t ++blktap_sysfs_store_pool(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t size) ++{ ++ struct blktap *tap = dev_get_drvdata(dev); ++ struct blktap_page_pool *pool, *tmp = tap->pool; ++ ++ if (tap->device.gd) ++ return -EBUSY; ++ ++ pool = blktap_page_pool_get(buf); ++ if (IS_ERR(pool)) ++ return PTR_ERR(pool); ++ ++ tap->pool = pool; ++ kobject_put(&tmp->kobj); ++ ++ return size; ++} ++DEVICE_ATTR(pool, S_IRUSR|S_IWUSR, ++ blktap_sysfs_show_pool, blktap_sysfs_store_pool); ++ ++int ++blktap_sysfs_create(struct blktap *tap) ++{ ++ struct blktap_ring *ring = &tap->ring; ++ struct device *dev; ++ int err = 0; ++ ++ init_waitqueue_head(&tap->remove_wait); ++ ++ dev = device_create(class, NULL, ring->devno, ++ tap, "blktap%d", tap->minor); ++ if (IS_ERR(dev)) ++ err = PTR_ERR(dev); ++ if (!err) ++ err = device_create_file(dev, &dev_attr_name); ++ if (!err) ++ err = device_create_file(dev, &dev_attr_remove); ++ if (!err) ++ err = device_create_file(dev, &dev_attr_pause); ++ if (!err) ++ err = device_create_file(dev, &dev_attr_resume); ++ if (!err) ++ err = device_create_file(dev, &dev_attr_debug); ++ if (!err) ++ err = device_create_file(dev, &dev_attr_task); ++ if (!err) ++ err = device_create_file(dev, &dev_attr_pool); ++ if (!err) ++ ring->dev = dev; ++ else ++ device_unregister(dev); ++ ++ return err; ++} ++ ++void ++blktap_sysfs_destroy(struct blktap *tap) ++{ ++ struct blktap_ring *ring = &tap->ring; ++ struct device *dev; ++ ++ dev = ring->dev; ++ ++ if (!dev) ++ return; ++ ++ dev_set_drvdata(dev, NULL); ++ wake_up(&tap->remove_wait); ++ ++ device_unregister(dev); ++ ring->dev = NULL; ++} ++ ++static ssize_t ++verbosity_show(struct class *class, ++ struct class_attribute *attr, ++ char *buf) ++{ ++ return sprintf(buf, "%d\n", blktap_debug_level); ++} ++ ++static ssize_t ++verbosity_store(struct class *class, ++ struct class_attribute *attr, ++ const char *buf, size_t size) ++{ ++ int level; ++ ++ if (sscanf(buf, "%d", &level) == 1) { ++ blktap_debug_level = level; ++ return size; ++ } ++ ++ return -EINVAL; ++} ++static CLASS_ATTR_RW(verbosity); ++ ++ ++static ssize_t ++devices_show(struct class *class, ++ struct class_attribute *attr, ++ char *buf) ++{ ++ int i, ret; ++ struct blktap *tap; ++ ++ mutex_lock(&blktap_lock); ++ ++ ret = 0; ++ for (i = 0; i < blktap_max_minor; i++) { ++ tap = blktaps[i]; ++ if (!tap) ++ continue; ++ ++ if (!test_bit(BLKTAP_DEVICE, &tap->dev_inuse)) ++ continue; ++ ++ ret += sprintf(buf + ret, "%d %s\n", tap->minor, tap->name); ++ } ++ ++ mutex_unlock(&blktap_lock); ++ ++ return ret; ++} ++static CLASS_ATTR_RO(devices); ++ ++void ++blktap_sysfs_exit(void) ++{ ++ if (class) ++ class_destroy(class); ++} ++ ++int __init ++blktap_sysfs_init(void) ++{ ++ struct class *cls; ++ int err = 0; ++ ++ cls = class_create(THIS_MODULE, "blktap2"); ++ if (IS_ERR(cls)) ++ err = PTR_ERR(cls); ++ if (!err) ++ err = class_create_file(cls, &class_attr_verbosity); ++ if (!err) ++ err = class_create_file(cls, &class_attr_devices); ++ if (!err) ++ class = cls; ++ else ++ class_destroy(cls); ++ ++ return err; ++} +--- /dev/null ++++ b/include/linux/blktap.h +@@ -0,0 +1,120 @@ ++/* ++ * Copyright (c) 2011, XenSource Inc. ++ * All rights reserved. ++ */ ++ ++#ifndef _LINUX_BLKTAP_H ++#define _LINUX_BLKTAP_H ++ ++/* ++ * Control ++ */ ++ ++#define BLKTAP_IOCTL_RESPOND 1 ++#define BLKTAP_IOCTL_ALLOC_TAP 200 ++#define BLKTAP_IOCTL_FREE_TAP 201 ++#define BLKTAP2_IOCTL_SET_PARAMS 203 ++#define BLKTAP2_IOCTL_PAUSE 204 ++#define BLKTAP2_IOCTL_REOPEN 205 ++#define BLKTAP2_IOCTL_RESUME 206 ++#define BLKTAP_IOCTL_CREATE_DEVICE 208 ++#define BLKTAP_IOCTL_REMOVE_DEVICE 207 ++ ++#define BLKTAP_DEVICE_FLAG_RO 0x00000001UL /* disk is R/O */ ++#define BLKTAP_DEVICE_FLAG_PSZ 0x00000002UL /* physical sector size */ ++#define BLKTAP_DEVICE_FLAG_FLUSH 0x00000004UL /* supports FLUSH */ ++#define BLKTAP_DEVICE_FLAG_TRIM 0x00000008UL /* supports TRIM */ ++ ++struct blktap_info { ++ unsigned int ring_major; ++ unsigned int bdev_major; ++ unsigned int ring_minor; ++}; ++ ++struct blktap_device_info { ++ unsigned long long capacity; ++ unsigned int sector_size; ++ unsigned long flags; ++ unsigned int phys_block_size; ++ unsigned int phys_block_offset; ++ unsigned int trim_block_size; ++ unsigned int trim_block_offset; ++}; ++ ++/* ++ * I/O ring ++ */ ++ ++#ifdef __KERNEL__ ++#define BLKTAP_PAGE_SIZE PAGE_SIZE ++#endif ++ ++#include ++ ++struct blktap_segment { ++ uint32_t __pad; ++ uint8_t first_sect; ++ uint8_t last_sect; ++}; ++ ++#define BLKTAP_OP_READ 0 ++#define BLKTAP_OP_WRITE 1 ++#define BLKTAP_OP_FLUSH 2 ++#define BLKTAP_OP_TRIM 3 ++ ++#define BLKTAP_SEGMENT_MAX 11 ++ ++struct blktap_ring_rw_request { ++ uint64_t sector_number; ++ struct blktap_segment seg[BLKTAP_SEGMENT_MAX]; ++}; ++ ++struct blktap_ring_tr_request { ++ uint64_t sector_number; ++ uint64_t nr_sectors; ++}; ++ ++struct blktap_ring_request { ++ uint8_t operation; ++ uint8_t nr_segments; ++ uint16_t __pad; ++ uint64_t id; ++ union { ++ struct blktap_ring_rw_request rw; ++ struct blktap_ring_tr_request tr; ++ } u; ++}; ++ ++#define BLKTAP_RSP_EOPNOTSUPP -2 ++#define BLKTAP_RSP_ERROR -1 ++#define BLKTAP_RSP_OKAY 0 ++ ++struct blktap_ring_response { ++ uint64_t id; ++ uint8_t operation; ++ int16_t status; ++}; ++ ++DEFINE_RING_TYPES(blktap, ++ struct blktap_ring_request, ++ struct blktap_ring_response); ++ ++#define BLKTAP_RING_SIZE __CONST_RING_SIZE(blktap, BLKTAP_PAGE_SIZE) ++ ++/* ++ * Ring messages + old ioctls (DEPRECATED) ++ */ ++ ++#define BLKTAP_RING_MESSAGE(_sring) \ ++ ((uint8_t*)(&(_sring)->rsp_event + 1)) ++#define BLKTAP_RING_MESSAGE_CLOSE 3 ++#define BLKTAP_IOCTL_CREATE_DEVICE_COMPAT 202 ++#define BLKTAP_NAME_MAX 256 ++ ++struct blktap2_params { ++ char name[BLKTAP_NAME_MAX]; ++ unsigned long long capacity; ++ unsigned long sector_size; ++}; ++ ++#endif /* _LINUX_BLKTAP_H */ diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/blktap2/blktap2.scc b/recipes-kernel/linux/files/openxt-kmeta/patches/blktap2/blktap2.scc new file mode 100644 index 0000000000..f4ef12ec99 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/blktap2/blktap2.scc @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: MIT +define KFEATURE_DESCRIPTION "Add blktap2 driver." +define KFEATURE_COMPATIBILITY all + +patch blktap2.patch + +kconf non-hardware blktap2.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-bridge-quirks/bridge-carrier-follow-prio0.patch b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-bridge-quirks/bridge-carrier-follow-prio0.patch new file mode 100644 index 0000000000..b509103de9 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-bridge-quirks/bridge-carrier-follow-prio0.patch @@ -0,0 +1,114 @@ +--- a/net/bridge/br_if.c ++++ b/net/bridge/br_if.c +@@ -86,6 +86,7 @@ void br_port_carrier_check(struct net_br + *notified = true; + } + } ++ br_maybe_copy_iface_carrier(p); + spin_unlock_bh(&br->lock); + } + +@@ -746,6 +747,31 @@ void br_port_flags_change(struct net_bri + br_recalculate_neigh_suppress_enabled(br); + } + ++/* if p->priority == 0 either copy carier if p is forwarding ++ * or set carrier to off if p is is not forwarding ++ * */ ++int br_maybe_copy_iface_carrier(struct net_bridge_port *p) ++{ ++ int carrier; ++ if (p->priority == 0) { ++ if (p->state == BR_STATE_FORWARDING) ++ carrier = netif_carrier_ok(p->dev); ++ else ++ carrier = 0; ++ if (carrier != netif_carrier_ok(p->br->dev)) { ++ printk("prio 0 port %s carrier %s, update bridge %s state\n", ++ p->dev->name, carrier ? "on" : "off", ++ p->br->dev->name); ++ if (carrier) ++ netif_carrier_on(p->br->dev); ++ else ++ netif_carrier_off(p->br->dev); ++ } ++ return 1; ++ } ++ return 0; ++} ++ + bool br_port_flag_is_set(const struct net_device *dev, unsigned long flag) + { + struct net_bridge_port *p; +--- a/net/bridge/br_private.h ++++ b/net/bridge/br_private.h +@@ -623,6 +623,7 @@ netdev_features_t br_features_recompute( + void br_port_flags_change(struct net_bridge_port *port, unsigned long mask); + void br_manage_promisc(struct net_bridge *br); + int nbp_backup_change(struct net_bridge_port *p, struct net_device *backup_dev); ++extern int br_maybe_copy_iface_carrier(struct net_bridge_port *p); + + /* br_input.c */ + int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb); +--- a/net/bridge/br_stp.c ++++ b/net/bridge/br_stp.c +@@ -466,8 +466,13 @@ void br_port_state_selection(struct net_ + + if (liveports == 0) + netif_carrier_off(br->dev); +- else +- netif_carrier_on(br->dev); ++ else { ++ int carrier_copied = 0; ++ list_for_each_entry(p, &br->port_list, list) ++ carrier_copied |= br_maybe_copy_iface_carrier(p); ++ if (!carrier_copied) ++ netif_carrier_on(br->dev); ++ } + } + + /* called under bridge lock */ +--- a/net/bridge/br_stp_if.c ++++ b/net/bridge/br_stp_if.c +@@ -316,6 +316,7 @@ int br_stp_set_port_priority(struct net_ + br_port_state_selection(p->br); + } + ++ br_maybe_copy_iface_carrier(p); + return 0; + } + +--- a/net/bridge/br_sysfs_br.c ++++ b/net/bridge/br_sysfs_br.c +@@ -345,6 +345,23 @@ static ssize_t no_linklocal_learn_store( + } + static DEVICE_ATTR_RW(no_linklocal_learn); + ++static int set_link_state(struct net_bridge *br, unsigned long val) ++{ ++ if (val) ++ netif_carrier_on(br->dev); ++ else ++ netif_carrier_off(br->dev); ++ return 0; ++} ++ ++static ssize_t store_link_state(struct device *d, ++ struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ return store_bridge_parm(d, buf, len, set_link_state); ++} ++static DEVICE_ATTR(link_state, S_IWUSR, NULL, store_link_state); ++ + #ifdef CONFIG_BRIDGE_IGMP_SNOOPING + static ssize_t multicast_router_show(struct device *d, + struct device_attribute *attr, char *buf) +@@ -864,6 +881,7 @@ static struct attribute *bridge_attrs[] + &dev_attr_gc_timer.attr, + &dev_attr_group_addr.attr, + &dev_attr_flush.attr, ++ &dev_attr_link_state.attr, + &dev_attr_no_linklocal_learn.attr, + #ifdef CONFIG_BRIDGE_IGMP_SNOOPING + &dev_attr_multicast_router.attr, diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-bridge-quirks/openxt-bridge-quirks.scc b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-bridge-quirks/openxt-bridge-quirks.scc new file mode 100644 index 0000000000..cb094bf7a6 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-bridge-quirks/openxt-bridge-quirks.scc @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: MIT +define KFEATURE_DESCRIPTION "Apply OpenXT bridge quirks." +define KFEATURE_COMPATIBILITY all + +# Change the bridge carrier state according to the priority 0 forwarding port. +patch bridge-carrier-follow-prio0.patch + +# Cmdline option to have the bridge pass copy of the skb and release the initial one. +## TODO: determine if this is necessary (not enabled by default in any vm) +patch skb-forward-copy-bridge-param.patch diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-bridge-quirks/skb-forward-copy-bridge-param.patch b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-bridge-quirks/skb-forward-copy-bridge-param.patch new file mode 100644 index 0000000000..b7999820fc --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-bridge-quirks/skb-forward-copy-bridge-param.patch @@ -0,0 +1,84 @@ +################################################################################ +SHORT DESCRIPTION: +################################################################################ +Add a module parameter to enable skb forward copy. + +################################################################################ +LONG DESCRIPTION: +################################################################################ +When the parameter is enabled, the bridge will pass copy of the skb and release +the initial one. + +################################################################################ +CHANGELOG +################################################################################ +Original author: Ross Phillipson +Port to 3.18: Eric Chanudet +Port to 4.14: Richard Turner +Port to 4.19: Richard Turner + +################################################################################ +REMOVAL +################################################################################ +? + +################################################################################ +UPSTREAM PLAN +################################################################################ +None. + +################################################################################ +INTERNAL DEPENDENCIES +################################################################################ +None. + +################################################################################ +PATCHES +################################################################################ +--- a/net/bridge/br_forward.c ++++ b/net/bridge/br_forward.c +@@ -7,6 +7,7 @@ + * Lennert Buytenhek + */ + ++#include + #include + #include + #include +@@ -17,6 +18,10 @@ + #include + #include "br_private.h" + ++static int br_skb_forward_copy = 0; ++module_param_named(skb_forward_copy, br_skb_forward_copy, uint, S_IRUGO); ++MODULE_PARM_DESC(skb_forward_copy, "Enable or disable SKB copying on forward path"); ++ + /* Don't forward packets to originating port or forwarding disabled */ + static inline int should_deliver(const struct net_bridge_port *p, + const struct sk_buff *skb) +@@ -32,6 +37,8 @@ static inline int should_deliver(const s + + int br_dev_queue_push_xmit(struct net *net, struct sock *sk, struct sk_buff *skb) + { ++ struct sk_buff *new_skb; ++ + skb_push(skb, ETH_HLEN); + if (!is_skb_forwardable(skb->dev, skb)) + goto drop; +@@ -49,7 +56,15 @@ int br_dev_queue_push_xmit(struct net *n + skb_set_network_header(skb, depth); + } + +- dev_queue_xmit(skb); ++ if (!br_skb_forward_copy) ++ dev_queue_xmit(skb); ++ else { ++ new_skb = skb_copy(skb, GFP_ATOMIC); ++ if (new_skb) { ++ dev_queue_xmit(new_skb); ++ kfree_skb(skb); ++ } ++ } + + return 0; + diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-input-quirks/extra-mt-input-devices.patch b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-input-quirks/extra-mt-input-devices.patch new file mode 100644 index 0000000000..df973de7ea --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-input-quirks/extra-mt-input-devices.patch @@ -0,0 +1,59 @@ +################################################################################ +SHORT DESCRIPTION: +################################################################################ +Add the Mosart 7105 MT multitouch input device (Panasonic CF-C1 systems). + +################################################################################ +LONG DESCRIPTION: +################################################################################ +Add the Mosart 7105 MT multitouch input device to support Panasonic CF-C1 +systems in hid-ids.h list. + +################################################################################ +CHANGELOG +################################################################################ +Original Author: Ross Philipson +Port to 3.18: Eric Chanudet +Port to 4.14: Richard Turner + +################################################################################ +REMOVAL +################################################################################ +Depending on the HCL, MOsart 7105 MT multitouch input device is supported or +not. + +################################################################################ +UPSTREAM PLAN +################################################################################ +None. + +################################################################################ +INTERNAL DEPENDENCIES +################################################################################ +None. + +################################################################################ +PATCHES +################################################################################ +--- a/drivers/hid/hid-ids.h ++++ b/drivers/hid/hid-ids.h +@@ -1177,6 +1177,7 @@ + #define USB_DEVICE_ID_TURBOX_KEYBOARD 0x0201 + #define USB_DEVICE_ID_ASUS_MD_5110 0x5110 + #define USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART 0x7100 ++#define USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART5 0x7105 + + #define USB_VENDOR_ID_TWINHAN 0x6253 + #define USB_DEVICE_ID_TWINHAN_IR_REMOTE 0x0100 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -2025,6 +2025,9 @@ static const struct hid_device_id mt_dev + { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, + MT_USB_DEVICE(USB_VENDOR_ID_TURBOX, + USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) }, ++ { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, ++ HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, ++ USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART5) }, + + /* Novatek Panel */ + { .driver_data = MT_CLS_NSMU, diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-input-quirks/openxt-input-quirks.scc b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-input-quirks/openxt-input-quirks.scc new file mode 100644 index 0000000000..71b016bba7 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-input-quirks/openxt-input-quirks.scc @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: MIT +define KFEATURE_DESCRIPTION "Apply OpenXT input quirks." +define KFEATURE_COMPATIBILITY all + +# TODO: determine if this is necessary (device still relevant?) +patch extra-mt-input-devices.patch diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-pci-quirks/konrad-ioperm.patch b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-pci-quirks/konrad-ioperm.patch new file mode 100644 index 0000000000..e01e5eafc8 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-pci-quirks/konrad-ioperm.patch @@ -0,0 +1,251 @@ +################################################################################ +SHORT DESCRIPTION: +################################################################################ +Paravirtualize IO permission bitmap. + +################################################################################ +LONG DESCRIPTION: +################################################################################ +See: +http://old-list-archives.xen.org/archives/html/xen-devel/2009-05/msg01139.html + +A PV Xen guest kernel has no TSS of its own, so the IO permission +bitmap must be paravirtualized. This patch adds set_io_bitmap +as a paravirt op, and defines a native version which updates the tss, +and a Xen version which uses a hypercall. + +This is much easier now that 32 and 64-bit use the same code to +manage the IO bitmap. + +################################################################################ +CHANGELOG +################################################################################ +Original author: Konrad Rzeszutek Wilk +Port to 3.18: Eric Chanudet +Port to 4.14: Richard Turner +Port to 4.19: Richard Turner + +################################################################################ +REMOVAL +################################################################################ +Until fixed upstream or for non-pv service VM pass-through. + +################################################################################ +UPSTREAM PLAN +################################################################################ +None. + +################################################################################ +INTERNAL DEPENDENCIES +################################################################################ +PIO passthrough in PV guests. + +################################################################################ +PATCHES +################################################################################ +--- a/arch/x86/include/asm/paravirt.h ++++ b/arch/x86/include/asm/paravirt.h +@@ -299,6 +299,12 @@ static inline void set_iopl_mask(unsigne + PVOP_VCALL1(cpu.set_iopl_mask, mask); + } + ++static inline void set_io_bitmap(struct thread_struct *thread, ++ unsigned long bytes_updated) ++{ ++ PVOP_VCALL2(cpu.set_io_bitmap, thread, bytes_updated); ++} ++ + static inline void paravirt_activate_mm(struct mm_struct *prev, + struct mm_struct *next) + { +--- a/arch/x86/include/asm/paravirt_types.h ++++ b/arch/x86/include/asm/paravirt_types.h +@@ -141,6 +141,8 @@ struct pv_cpu_ops { + void (*load_sp0)(unsigned long sp0); + + void (*set_iopl_mask)(unsigned mask); ++ void (*set_io_bitmap)(struct thread_struct *thread, ++ unsigned long bytes_updated); + + void (*wbinvd)(void); + +--- a/arch/x86/include/asm/processor.h ++++ b/arch/x86/include/asm/processor.h +@@ -534,6 +534,9 @@ static inline void native_set_iopl_mask( + #endif + } + ++extern void native_set_io_bitmap(struct thread_struct *thread, ++ unsigned long updated_bytes); ++ + static inline void + native_load_sp0(unsigned long sp0) + { +@@ -574,6 +577,12 @@ static inline void load_sp0(unsigned lon + } + + #define set_iopl_mask native_set_iopl_mask ++ ++static inline void set_io_bitmap(struct thread_struct *thread, ++ unsigned long updated_bytes) ++{ ++ native_set_io_bitmap(thread, updated_bytes); ++} + #endif /* CONFIG_PARAVIRT_XXL */ + + /* Free all resources held by a thread. */ +--- a/arch/x86/kernel/ioport.c ++++ b/arch/x86/kernel/ioport.c +@@ -21,13 +21,29 @@ + #include + #include + ++void native_set_io_bitmap(struct thread_struct *t, ++ unsigned long bytes_updated) ++{ ++ struct tss_struct *tss; ++ ++ if (!bytes_updated) ++ return; ++ ++ tss = &per_cpu(cpu_tss_rw, get_cpu()); ++ ++ /* Update the TSS: */ ++ if (t->io_bitmap_ptr) ++ memcpy(tss->io_bitmap, t->io_bitmap_ptr, bytes_updated); ++ else ++ memset(tss->io_bitmap, 0xff, bytes_updated); ++} ++ + /* + * this changes the io permissions bitmap in the current task. + */ + long ksys_ioperm(unsigned long from, unsigned long num, int turn_on) + { + struct thread_struct *t = ¤t->thread; +- struct tss_struct *tss; + unsigned int i, max_long, bytes, bytes_updated; + + if ((from + num <= from) || (from + num > IO_BITMAP_BITS)) +@@ -63,13 +79,13 @@ long ksys_ioperm(unsigned long from, uns + } + + /* +- * do it in the per-thread copy and in the TSS ... ++ * do it in the per-thread copy + * +- * Disable preemption via get_cpu() - we must not switch away ++ * Disable preemption - we must not switch away + * because the ->io_bitmap_max value must match the bitmap + * contents: + */ +- tss = &per_cpu(cpu_tss_rw, get_cpu()); ++ preempt_disable(); + + if (turn_on) + bitmap_clear(t->io_bitmap_ptr, from, num); +@@ -90,10 +106,9 @@ long ksys_ioperm(unsigned long from, uns + + t->io_bitmap_max = bytes; + +- /* Update the TSS: */ +- memcpy(tss->io_bitmap, t->io_bitmap_ptr, bytes_updated); ++ set_io_bitmap(t, bytes_updated); + +- put_cpu(); ++ preempt_enable(); + + return 0; + } +--- a/arch/x86/kernel/paravirt.c ++++ b/arch/x86/kernel/paravirt.c +@@ -342,6 +342,7 @@ struct paravirt_patch_template pv_ops = + .cpu.swapgs = native_swapgs, + + .cpu.set_iopl_mask = native_set_iopl_mask, ++ .cpu.set_io_bitmap = native_set_io_bitmap, + + .cpu.start_context_switch = paravirt_nop, + .cpu.end_context_switch = paravirt_nop, +--- a/arch/x86/kernel/process.c ++++ b/arch/x86/kernel/process.c +@@ -114,16 +114,12 @@ void exit_thread(struct task_struct *tsk + struct fpu *fpu = &t->fpu; + + if (bp) { +- struct tss_struct *tss = &per_cpu(cpu_tss_rw, get_cpu()); +- ++ preempt_disable(); + t->io_bitmap_ptr = NULL; + clear_thread_flag(TIF_IO_BITMAP); +- /* +- * Careful, clear this in the TSS too: +- */ +- memset(tss->io_bitmap, 0xff, t->io_bitmap_max); ++ set_io_bitmap(t, t->io_bitmap_max); + t->io_bitmap_max = 0; +- put_cpu(); ++ preempt_enable(); + kfree(bp); + } + +@@ -273,26 +269,10 @@ static inline void switch_to_bitmap(stru + struct thread_struct *next, + unsigned long tifp, unsigned long tifn) + { +- struct tss_struct *tss = this_cpu_ptr(&cpu_tss_rw); +- +- if (tifn & _TIF_IO_BITMAP) { +- /* +- * Copy the relevant range of the IO bitmap. +- * Normally this is 128 bytes or less: +- */ +- memcpy(tss->io_bitmap, next->io_bitmap_ptr, +- max(prev->io_bitmap_max, next->io_bitmap_max)); +- /* +- * Make sure that the TSS limit is correct for the CPU +- * to notice the IO bitmap. +- */ +- refresh_tss_limit(); +- } else if (tifp & _TIF_IO_BITMAP) { +- /* +- * Clear any possible leftover bits: +- */ +- memset(tss->io_bitmap, 0xff, prev->io_bitmap_max); +- } ++ if ((tifn & _TIF_IO_BITMAP) || ++ (tifp & _TIF_IO_BITMAP)) ++ set_io_bitmap(next, ++ max(prev->io_bitmap_max, next->io_bitmap_max)); + } + + #ifdef CONFIG_SMP +--- a/arch/x86/xen/enlighten_pv.c ++++ b/arch/x86/xen/enlighten_pv.c +@@ -846,6 +846,18 @@ void xen_set_iopl_mask(unsigned mask) + HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl); + } + ++static void xen_set_io_bitmap(struct thread_struct *thread, ++ unsigned long bytes_updated) ++{ ++ struct physdev_set_iobitmap set_iobitmap; ++ ++ set_xen_guest_handle(set_iobitmap.bitmap, ++ (char *)thread->io_bitmap_ptr); ++ set_iobitmap.nr_ports = thread->io_bitmap_ptr ? IO_BITMAP_BITS : 0; ++ WARN_ON(HYPERVISOR_physdev_op(PHYSDEVOP_set_iobitmap, ++ &set_iobitmap)); ++} ++ + static void xen_io_delay(void) + { + } +@@ -1057,6 +1069,7 @@ static const struct pv_cpu_ops xen_cpu_o + .load_sp0 = xen_load_sp0, + + .set_iopl_mask = xen_set_iopl_mask, ++ .set_io_bitmap = xen_set_io_bitmap, + .io_delay = xen_io_delay, + + /* Xen takes care of %gs when switching to usermode for us */ diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-pci-quirks/openxt-pci-quirks.scc b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-pci-quirks/openxt-pci-quirks.scc new file mode 100644 index 0000000000..4ccd0c2311 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-pci-quirks/openxt-pci-quirks.scc @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: MIT +define KFEATURE_DESCRIPTION "Apply OpenXT PCI quirks." +define KFEATURE_COMPATIBILITY all + +# Align start address of PCI resources passed-through. +# TODO: determine if this is necessary +patch pci-pt-move-unaligned-resources.patch + +# FLR quirks for VGA devices +# TODO: determine if this is necessary. Half of the patch relates to IGD, which is not supported for pass-through. +patch pci-pt-flr.patch + +# Paravirtualize IO permission bitmap. +patch konrad-ioperm.patch + +# handle reverting setting the policy to permissive for a pci device passed-through via pciback/pcifront. +patch pciback-restrictive-attr.patch + +# Exhaust all PCI device reset options after being passed through. +patch thorough-reset-interface-to-pciback-s-sysfs.patch diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-pci-quirks/pci-pt-flr.patch b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-pci-quirks/pci-pt-flr.patch new file mode 100644 index 0000000000..4eadaf0ecd --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-pci-quirks/pci-pt-flr.patch @@ -0,0 +1,105 @@ +################################################################################ +SHORT DESCRIPTION: +################################################################################ +PCI pass-through quirks for FLR. + +################################################################################ +LONG DESCRIPTION: +################################################################################ +Couple of quirks for FLR: +_ Wait 500ms (instead of 200ms defined in specs?) for VGA/Display video + controllers FLR. + +_ Ivy Bridge Intel Graphic Device: + * Force enable response in memory before FLR. + * Restore command register and return ENOTTY so generic reset logic can be + run after the quirk. + +################################################################################ +CHANGELOG +################################################################################ +Original author: James McKenzie +Port to 3.18: Eric Chanudet +Port to 4.14: Richard Turner +Port to 4.19: Richard Turner + +################################################################################ +REMOVAL +################################################################################ +This patch is related to Intel Graphic Devices only. + +################################################################################ +UPSTREAM PLAN +################################################################################ +None. + +################################################################################ +INTERNAL DEPENDENCIES +################################################################################ +None. + +################################################################################ +PATCHES +################################################################################ +--- a/drivers/pci/pci.c ++++ b/drivers/pci/pci.c +@@ -5055,7 +5055,12 @@ int pci_probe_reset_function(struct pci_ + if (rc != -ENOTTY) + return rc; + +- return pci_parent_bus_reset(dev, 1); ++ rc = pci_parent_bus_reset(dev, 1); ++ /* larger delay for gpus */ ++ if (dev->class == 0x30000 || dev->class == 0x38000) ++ msleep(500); ++ return rc; ++ + } + + /** +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -3764,10 +3764,15 @@ static int reset_ivb_igd(struct pci_dev + void __iomem *mmio_base; + unsigned long timeout; + u32 val; ++ u16 cmd; + + if (probe) + return 0; + ++ /* enable response in memory space */ ++ pci_read_config_word(dev, PCI_COMMAND, &cmd); ++ pci_write_config_word(dev, PCI_COMMAND, cmd | PCI_COMMAND_MEMORY); ++ + mmio_base = pci_iomap(dev, 0, 0); + if (!mmio_base) + return -ENOMEM; +@@ -3798,7 +3803,10 @@ reset_complete: + iowrite32(0x00000002, mmio_base + NSDE_PWR_STATE); + + pci_iounmap(dev, mmio_base); +- return 0; ++ pci_write_config_word(dev, PCI_COMMAND, cmd); ++ /* follow with regular flr, returning ENOTTY causes rest of the FLR non-device specific code ++ to execute. Alternatively we could execute it here explicitly and mby that would be cleaner */ ++ return -ENOTTY; + } + + /* Device-specific reset method for Chelsio T4-based adapters */ +--- a/drivers/xen/xen-pciback/pci_stub.c ++++ b/drivers/xen/xen-pciback/pci_stub.c +@@ -417,10 +417,13 @@ static int pcistub_init_device(struct pc + if (!dev_data->pci_saved_state) + dev_err(&dev->dev, "Could not store PCI conf saved state!\n"); + else { ++#if 0 + dev_dbg(&dev->dev, "resetting (FLR, D3, etc) the device\n"); + __pci_reset_function_locked(dev); + pci_restore_state(dev); ++#endif + } ++ + /* Now disable the device (this also ensures some private device + * data is setup before we export) + */ diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-pci-quirks/pci-pt-move-unaligned-resources.patch b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-pci-quirks/pci-pt-move-unaligned-resources.patch new file mode 100644 index 0000000000..c349341652 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-pci-quirks/pci-pt-move-unaligned-resources.patch @@ -0,0 +1,78 @@ +################################################################################ +SHORT DESCRIPTION: +################################################################################ +Align start address of PCI resources passed through. + +################################################################################ +LONG DESCRIPTION: +################################################################################ +In some cases, the resource's start address is not page-aligned at this point. +Pass-through to the guest will then fail. This patch makes sure this odd +behaviour does not happen. + +################################################################################ +CHANGELOG +################################################################################ +Original author: Tomasz Wroblewski +Port to 3.18: Eric Chanudet +Port to 4.14: Richard Turner +Port to 4.19: Richard Turner + +################################################################################ +REMOVAL +################################################################################ +This is a work-around for a corner case, more testing should be done to figure +out if it still happens and why. + +################################################################################ +UPSTREAM PLAN +################################################################################ +None, this is an OpenXT work-around. + +################################################################################ +INTERNAL DEPENDENCIES +################################################################################ +PCI pass-through, depending on the device. + +################################################################################ +PATCHES +################################################################################ +--- a/drivers/pci/pci.c ++++ b/drivers/pci/pci.c +@@ -6111,6 +6111,27 @@ void __weak pci_resource_to_user(const s + static char *resource_alignment_param; + static DEFINE_SPINLOCK(resource_alignment_lock); + ++static ++resource_size_t pci_auto_resource_alignment(struct pci_dev *dev) ++{ ++ int i; ++ struct resource *r; ++ if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || ++ (dev->hdr_type == PCI_HEADER_TYPE_NORMAL && ++ (dev->class >> 8) == PCI_CLASS_BRIDGE_HOST)) ++ return 0; ++ ++ /* move resources only if they are not page aligned */ ++ for (i = 0; i < PCI_BRIDGE_RESOURCES; ++i) { ++ r = &dev->resource[i]; ++ if (!(r->flags & IORESOURCE_MEM)) ++ continue; ++ if (r->start & (PAGE_SIZE-1)) ++ return PAGE_SIZE; ++ } ++ return 0; ++} ++ + /** + * pci_specified_resource_alignment - get resource alignment specified by user. + * @dev: the PCI device to get +@@ -6168,6 +6189,8 @@ static resource_size_t pci_specified_res + } + p++; + } ++ if (align < PAGE_SIZE) ++ align = pci_auto_resource_alignment(dev); + out: + spin_unlock(&resource_alignment_lock); + return align; diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-pci-quirks/pciback-restrictive-attr.patch b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-pci-quirks/pciback-restrictive-attr.patch new file mode 100644 index 0000000000..dd807a8854 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-pci-quirks/pciback-restrictive-attr.patch @@ -0,0 +1,98 @@ +--- a/drivers/xen/xen-pciback/pci_stub.c ++++ b/drivers/xen/xen-pciback/pci_stub.c +@@ -1370,15 +1370,14 @@ out: + } + static DRIVER_ATTR_RW(quirks); + +-static ssize_t permissive_store(struct device_driver *drv, const char *buf, +- size_t count) ++static int set_confspace_policy(const char *dev_str, bool permissive) + { + int domain, bus, slot, func; + int err; + struct pcistub_device *psdev; + struct xen_pcibk_dev_data *dev_data; + +- err = str_to_slot(buf, &domain, &bus, &slot, &func); ++ err = str_to_slot(dev_str, &domain, &bus, &slot, &func); + if (err) + goto out; + +@@ -1394,22 +1393,33 @@ static ssize_t permissive_store(struct d + err = -ENXIO; + goto release; + } +- if (!dev_data->permissive) { +- dev_data->permissive = 1; ++ ++ if (!dev_data->permissive && permissive) { + /* Let user know that what they're doing could be unsafe */ + dev_warn(&psdev->dev->dev, "enabling permissive mode " + "configuration space accesses!\n"); + dev_warn(&psdev->dev->dev, + "permissive mode is potentially unsafe!\n"); + } ++ dev_data->permissive = permissive; + release: + pcistub_device_put(psdev); + out: +- if (!err) +- err = count; + return err; + } + ++static ssize_t permissive_store(struct device_driver *drv, const char *buf, ++ size_t count) ++{ ++ int err; ++ ++ err = set_confspace_policy(buf, true); ++ if (err) { ++ return err; ++ } ++ return count; ++} ++ + static ssize_t permissive_show(struct device_driver *drv, char *buf) + { + struct pcistub_device *psdev; +@@ -1434,6 +1444,20 @@ static ssize_t permissive_show(struct de + } + static DRIVER_ATTR_RW(permissive); + ++static ssize_t restrictive_store(struct device_driver *drv, const char *buf, ++ size_t count) ++{ ++ int err; ++ ++ err = set_confspace_policy(buf, false); ++ if (err) { ++ return err; ++ } ++ return count; ++} ++static DRIVER_ATTR_WO(restrictive); ++ ++ + static void pcistub_exit(void) + { + driver_remove_file(&xen_pcibk_pci_driver.driver, &driver_attr_new_slot); +@@ -1442,6 +1466,8 @@ static void pcistub_exit(void) + driver_remove_file(&xen_pcibk_pci_driver.driver, &driver_attr_slots); + driver_remove_file(&xen_pcibk_pci_driver.driver, &driver_attr_quirks); + driver_remove_file(&xen_pcibk_pci_driver.driver, ++ &driver_attr_restrictive); ++ driver_remove_file(&xen_pcibk_pci_driver.driver, + &driver_attr_permissive); + driver_remove_file(&xen_pcibk_pci_driver.driver, + &driver_attr_irq_handlers); +@@ -1533,6 +1559,9 @@ static int __init pcistub_init(void) + if (!err) + err = driver_create_file(&xen_pcibk_pci_driver.driver, + &driver_attr_permissive); ++ if (!err) ++ err = driver_create_file(&xen_pcibk_pci_driver.driver, ++ &driver_attr_restrictive); + + if (!err) + err = driver_create_file(&xen_pcibk_pci_driver.driver, diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-pci-quirks/thorough-reset-interface-to-pciback-s-sysfs.patch b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-pci-quirks/thorough-reset-interface-to-pciback-s-sysfs.patch new file mode 100644 index 0000000000..9b8ae3fc3b --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-pci-quirks/thorough-reset-interface-to-pciback-s-sysfs.patch @@ -0,0 +1,513 @@ +From d686351d8ea4a1ea1d755d0a10f6f14d1c870911 Mon Sep 17 00:00:00 2001 +From: Kate Temkin +Date: Wed, 8 Apr 2015 00:58:24 -0400 +Subject: [PATCH] Add thorough reset interface to pciback's sysfs. + +-------------------------------------------------------------------------------- +SHORT DESCRIPTION: +-------------------------------------------------------------------------------- +Adds an interface that allows "more thorough" resets to be performed +on devices which don't support Function Level Resets (FLRs). This +interface should allow the toolstack to ensure that a PCI device is in a +known state prior to passing it through to a VM. + +-------------------------------------------------------------------------------- +LONG DESCRIPTION: +-------------------------------------------------------------------------------- + +From Konrad Rzeszutek Wilk's original post to xen-devel and the LKML: + + The life-cycle of a PCI device in Xen pciback is complex + and is constrained by the PCI generic locking mechanism. + + It starts with the device being binded to us - for which + we do a device function reset (and done via SysFS + so the PCI lock is held) + + If the device is unbinded from us - we also do a function + reset (also done via SysFS so the PCI lock is held). + + If the device is un-assigned from a guest - we do a function + reset (no PCI lock). + + All on the individual PCI function level (so bus:device:function). + + Unfortunatly a function reset is not adequate for certain + PCIe devices. The reset for an individual PCI function "means + device must support FLR (PCIe or AF), PM reset on D3hot->D0 + device specific reset, or be a singleton device on a bus + a secondary bus reset. FLR does not have widespread support, + reset is not very reliable, and bus topology is dictated by the + and device design. We need to provide a means for a user to + a bus reset in cases where the existing mechanisms are not + or not reliable. " (Adam Williamson, 'vfio-pci: PCI hot reset + interface' commit 8b27ee60bfd6bbb84d2df28fa706c5c5081066ca). + + As such to do a slot or a bus reset is we need another mechanism. + This is not exposed SysFS as there is no good way of exposing + a bus topology there. + + This is due to the complexity - we MUST know that the different + functions off a PCIe device are not in use by other drivers, or + if they are in use (say one of them is assigned to a guest + and the other is idle) - it is still OK to reset the slot + (assuming both of them are owned by Xen pciback). + + This patch does that by doing an slot or bus reset (if + slot not supported) if all of the functions of a PCIe + device belong to Xen PCIback. We do not care if the device is + in-use as we depend on the toolstack to be aware of this - + however if it is we will WARN the user. + + Due to the complexity with the PCI lock we cannot do + the reset when a device is binded ('echo $BDF > bind') + or when unbinded ('echo $BDF > unbind') as the pci_[slot|bus]_reset + also take the same lock resulting in a dead-lock. + + Putting the reset function in a workqueue or thread + won't work either - as we have to do the reset function + outside the 'unbind' context (it holds the PCI lock). + But once you 'unbind' a device the device is no longer + under the ownership of Xen pciback and the pci_set_drvdata + has been reset so we cannot use a thread for this. + + Instead of doing all this complex dance, we depend on the toolstack + doing the right thing. As such implement [... a SysFS attribute] + which [... the toolstack] uses when a device is detached or attached + from/to a guest. It bypasses the need to worry about the PCI lock. + + To not inadvertly do a bus reset that would affect devices that + are in use by other drivers (other than Xen pciback) prior + to the reset we check that all of the devices under the bridge + are owned by Xen pciback. If they are not we do not do + the bus (or slot) reset. + + We also warn the user if the device is in use - but still + continue with the reset. This should not happen as the toolstack + also does the check. + +-- + +Our version of the patch has been modified to use a less confusing +sysfs name. The original name ('do_flr') is inappropriate, as it +implies a function level reset; it is entirely possible that the patch +code will use a bus-level reset when appropriate. + +The new sysfs entry is located at: + + /sys/bus/pci/drivers/pciback/reset_device + +and can be activated by writing a domain:bus:device:function device +identifier into the sysfs file. As an example: + + echo "0000:01:00.0" > /sys/bus/pci/drivers/pciback/reset_device + +would reset the device matching the D:BDF descriptor above. + +-------------------------------------------------------------------------------- +CHANGELOG: +-------------------------------------------------------------------------------- +This is a port of a patch that likely had many authors, including: + -Konrad Rzeszutek Wilk + -Alex Williamson + -Ross Phillipson +Ported to OpenXT by: Kyle J. Temkin , 4/8/15 +Rewrite by: Kyle J. Temkin , 4/10/15 + +-------------------------------------------------------------------------------- +DEPENDENCIES +-------------------------------------------------------------------------------- +This patch requires ONE of the following: + -A relatively modern linux kernel (3.18+) as a base; which provides + the PCI functions used; or + -Our PCI reset backports patch (backport-pci-reset-functionality.patch), + which backports the relevant functionality to 3.11. + +To take advantage of this patch, the utilized toolstack should be +changed to: + -Use the provided "reset_device" property, rather than the PCI + device's sysfs "reset" entry. This enables resets beyond a FLR to be + used. + -Ensure that all functions of a given device are passed through + together. This allows us to use some of the more thorugh resetting + techniques, when possible. + +-------------------------------------------------------------------------------- +REMOVAL +-------------------------------------------------------------------------------- +This patch provides a service which is necessary for proper passthrough +of many PCI cards: a generalized ability to reset PCI devices, without +requiring that the device support FLR or power-management based resets. + +This patch will be necessary until either the Linux PCI subsystem or Xen +PCIback drivers are modified to provide this support; or until cards +without proper FLR support are no longer supported. + +-------------------------------------------------------------------------------- +UPSTREAM PLAN +-------------------------------------------------------------------------------- + +This code is taken from a patch which was originally proposed and +rejected from upstream on the LKML and xen-devel. An upstream +implementation of the functionality of this patch is still necessary; +and can and should be implemented. + +This patch will hopefully be replaced with an upstream version when +community concensus has produced a single "blessed" method of +accomplishing its functionality. + +-------------------------------------------------------------------------------- +PATCHES +-------------------------------------------------------------------------------- +--- + drivers/xen/xen-pciback/pci_stub.c | 338 ++++++++++++++++++++++++++++++++++--- + 1 file changed, 312 insertions(+), 26 deletions(-) + +--- a/drivers/xen/xen-pciback/pci_stub.c ++++ b/drivers/xen/xen-pciback/pci_stub.c +@@ -102,10 +102,8 @@ static void pcistub_device_release(struc + + xen_unregister_device_domain_owner(dev); + +- /* Call the reset function which does not take lock as this +- * is called from "unbind" which takes a device_lock mutex. +- */ +- __pci_reset_function_locked(dev); ++ /* Reset is done by the toolstack by using 'reset_device' on the ++ * SysFS. */ + if (dev_data && + pci_load_and_free_saved_state(dev, &dev_data->pci_saved_state)) + dev_info(&dev->dev, "Could not reload PCI state\n"); +@@ -126,9 +124,6 @@ static void pcistub_device_release(struc + err); + } + +- /* Disable the device */ +- xen_pcibk_reset_device(dev); +- + kfree(dev_data); + pci_set_drvdata(dev, NULL); + +@@ -225,6 +220,243 @@ struct pci_dev *pcistub_get_pci_dev_by_s + return found_dev; + } + ++ ++/** ++ * Returns true iff the given device supports PCIe FLRs. ++ */ ++static bool __device_supports_pcie_flr(struct pci_dev *dev) ++{ ++ u32 cap; ++ ++ /* ++ * Read the device's capabilities. Note that this can be used even on legacy ++ * PCI devices (and not just on PCIe devices)-- it indicates that no capabilities ++ * are supported if the device is legacy PCI by setting cap to 0. ++ */ ++ pcie_capability_read_dword(dev, PCI_EXP_DEVCAP, &cap); ++ ++ /* Return true iff the device advertises supporting an FLR. */ ++ return (cap & PCI_EXP_DEVCAP_FLR); ++} ++ ++ ++/** ++ * Returns true iff the given device supports PCI Advanced Functionality (AF) FLRs. ++ */ ++static bool __device_supports_pci_af_flr(struct pci_dev *dev) ++{ ++ int pos; ++ u8 capability_flags; ++ ++ /* First, try to find the location of the PCI Advanced Functionality capability byte. */ ++ pos = pci_find_capability(dev, PCI_CAP_ID_AF); ++ ++ /* ++ * If we weren't able to find the capability byte, this device doesn't support ++ * the Advanced Functionality extensions, and thus won't support AF FLR. ++ */ ++ if (!pos) ++ return false; ++ ++ /* Read the capabilities advertised in the AF capability byte. */ ++ pci_read_config_byte(dev, pos + PCI_AF_CAP, &capability_flags); ++ ++ /* ++ * If the device does support AF, it will advertise FLR support via the ++ * PCI_AF_CAP_FLR bit. We'll also check for the Transactions Pending (TP) ++ * mechanism, as the kernel requires this extension to issue an AF FLR. ++ * (Internally, the PCI reset code needs to be able to wait for all ++ * pending transactions to complete prior to issuing the AF FLR.) ++ */ ++ return (capability_flags & PCI_AF_CAP_TP) && (capability_flags & PCI_AF_CAP_FLR); ++} ++ ++ ++/** ++ * Returns true iff the given device adverstises supporting function- ++ * level-reset (FLR). ++ */ ++static bool device_supports_flr(struct pci_dev *dev) ++{ ++ return __device_supports_pci_af_flr(dev) || __device_supports_pcie_flr(dev); ++} ++ ++ ++/** ++ * Out argument for the __safe_to_sbr_device_callback function. ++ */ ++struct safe_to_sbr_arguments { ++ ++ //Stores the most recently encountered PCI device that does ++ //not belong to pciback. As used below, this is the result of a ++ //search for a non-pciback device on a bus; we stop upon finding ++ //the first non-pciback device. ++ struct pci_dev *last_non_pciback_device; ++ ++ //Stores the number of pciback devices that appear to be in use ++ //on the bus in question. ++ int use_count; ++ ++}; ++ ++ ++/** ++ * A callback function which determines if a given PCI device is owned by pciback, ++ * and whether the given device is in use. Used by safe_to_sbr_device. ++ * ++ * @param dev The PCI device to be checked. ++ * @param data An out argument of type struct safe_to_sbr_device_callback_arguments. ++ * Updated to indicate the result of the search. See the struct's definition ++ * for more details. ++ * ++ */ ++static int __safe_to_sbr_device_callback(struct pci_dev *dev, void *data) ++{ ++ ++ struct pcistub_device *psdev; ++ ++ bool device_owned_by_pciback = false; ++ struct safe_to_sbr_arguments *arg = data; ++ ++ unsigned long flags; ++ ++ //Ensure that we have exclusive access to the list of PCI devices, ++ //so we can traverse it. ++ spin_lock_irqsave(&pcistub_devices_lock, flags); ++ ++ //Iterate over all PCI devices owned by the pci stub. ++ list_for_each_entry(psdev, &pcistub_devices, dev_list) { ++ ++ //If the given device is owned by pciback... ++ if (psdev->dev == dev) { ++ ++ //mark it as a pciback device. ++ device_owned_by_pciback = true; ++ ++ //If we have a physical device associated with the pciback device, ++ //mark this device as in-use. ++ if (psdev->pdev) ++ arg->use_count++; ++ ++ //Stop searching; we've found a the PCIback device associated with this one. ++ break; ++ } ++ } ++ ++ //Release the PCI device lock... ++ spin_unlock_irqrestore(&pcistub_devices_lock, flags); ++ ++ //... and report if we've found a device that's not owned by pciback. ++ dev_dbg(&dev->dev, "%s\n", device_owned_by_pciback ? "is owned by pciback, and can be reset if not in use." ++ : "not owned by pciback, and thus cannot be reset."); ++ ++ //If we've found a device that's not owned by pciback, update our data ++ //argument so it points to the most recent unowned device. (We check ++ //this like a flag, later: if it's never set, no one owns the device!) ++ if (!device_owned_by_pciback) ++ arg->last_non_pciback_device = dev; ++ ++ //If we've found a device that's not owned by pciback, return false-- ++ //this indicates that pci_walk_bus should cease its walk. ++ return !device_owned_by_pciback; ++} ++ ++ ++/** ++ * Returns true iff it should be safe to issue a secondary bus reset ++ * to the device; that is, if an SBR can be issued without disrupting ++ * other devices. ++ */ ++static bool safe_to_sbr_device(struct pci_dev *dev) ++{ ++ struct safe_to_sbr_arguments walk_result = { .last_non_pciback_device = NULL, .use_count = 0 }; ++ ++ //Walk the PCI bus, attempting to find if any of the given devices ++ pci_walk_bus(dev->bus, __safe_to_sbr_device_callback, &walk_result); ++ ++ //If the device is in use, emit a warning error. ++ if(walk_result.use_count > 0) ++ dev_dbg(&dev->dev, "is in use; currently not safe to SBR device.\n"); ++ ++ //Return true iff we did not pick up any other devices ++ //that were either in use, or not owned by pciback. ++ return (walk_result.last_non_pciback_device == NULL) && (walk_result.use_count == 0); ++} ++ ++ ++/** ++ * Attempt a raw reset of the provided PCI device-- via any ++ * method available to us. This method prefers the gentlest ++ * possible reset method-- currently an FLR, which many ++ * PCIe devices should support. ++ * ++ * @param dev The pci device to be reset. ++ * @return Zero on success, or the error code generated by the reset method on failure. ++ */ ++static int __pcistub_raw_device_reset(struct pci_dev *dev) ++{ ++ //Determine if bus resetting techniques (SBR, slot resets) ++ //are safe, and thus should be allowed. ++ int allow_bus_reset = safe_to_sbr_device(dev); ++ ++ //If FLRs are supported; we'll try to let the linux kernel ++ //manually reset the device. ++ if(device_supports_flr(dev)) { ++ dev_dbg(&dev->dev, "Resetting device using an FLR."); ++ return pci_reset_function(dev); ++ } ++ ++ //pci_reset_bus will first attempt by slot, if unable, ++ //will attempt to reset the entire PCI bus ++ if(allow_bus_reset) { ++ dev_dbg(&dev->dev, "Resetting device using a slot or SBR"); ++ return pci_reset_bus(dev); ++ } ++ ++ //If we weren't able to reset the device by any of our known-good methods, ++ //fall back to the linux kernel's reset function. Unfortunately, this considers a ++ //power management reset to be a valid reset; though this doesn't work for many devices-- ++ //especially GPUs. ++ dev_err(&dev->dev, "No reset methods available for %s. Falling back to kernel reset.", pci_name(dev)); ++ pci_reset_function(dev); ++ ++ //Return an error code, indicating that we likely did not reset the device correctly. ++ return -ENOTTY; ++} ++ ++ ++/** ++ * Resets the target (pciback-owned) PCI device. Primarily intended ++ * for use by the toolstack, so it can ensure a consistent PCI device ++ * state on VM startup. ++ * ++ * @param dev The device to be reset. ++ * @return Zero on success, or a negated error code on failure. ++ */ ++static int pcistub_reset_pci_dev(struct pci_dev *dev) ++{ ++ int rc; ++ ++ if (!dev) ++ return -EINVAL; ++ ++ /* ++ * Takes the PCI lock. OK to do it as we are never called ++ * from 'unbind' state and don't deadlock. ++ */ ++ rc =__pcistub_raw_device_reset(dev); ++ pci_restore_state(dev); ++ ++ /* This disables the device. */ ++ xen_pcibk_reset_device(dev); ++ ++ /* And cleanup up our emulated fields. */ ++ xen_pcibk_config_reset_dev(dev); ++ return rc; ++} ++ ++ ++ + struct pci_dev *pcistub_get_pci_dev(struct xen_pcibk_device *pdev, + struct pci_dev *dev) + { +@@ -280,11 +512,13 @@ void pcistub_put_pci_dev(struct pci_dev + * pcistub and xen_pcibk when AER is in processing + */ + down_write(&pcistub_sem); +- /* Cleanup our device +- * (so it's ready for the next domain) +- */ + device_lock_assert(&dev->dev); +- __pci_reset_function_locked(dev); ++ /* ++ * Reset is up to the toolstack. ++ * The toolstack has to call 'reset_device' before ++ * providing the PCI device to a guest (see pcistub_reset_device). ++ */ ++ //__pci_reset_function_locked(dev); + + dev_data = pci_get_drvdata(dev); + ret = pci_load_saved_state(dev, dev_data->pci_saved_state); +@@ -1457,6 +1691,41 @@ static ssize_t restrictive_store(struct + } + static DRIVER_ATTR_WO(restrictive); + ++/** ++ * Handles the "reset_device" sysfs attribute. This is the primary reset interface ++ * utilized by the toolstack. ++ */ ++static ssize_t reset_device_store(struct device_driver *drv, const char *buf, size_t count) ++{ ++ int domain, bus, slot, func, err; ++ struct pcistub_device *psdev; ++ ++ //Attempt to convert the user's string to a BDF/slot. ++ err = str_to_slot(buf, &domain, &bus, &slot, &func); ++ if (err) ++ return -ENODEV; ++ ++ //... and then use that slot to find the pciback device. ++ psdev = pcistub_device_find(domain, bus, slot, func); ++ ++ //If we have a device, attempt to reset it using our internal reset path. ++ if (psdev) { ++ err = pcistub_reset_pci_dev(psdev->dev); ++ pcistub_device_put(psdev); ++ ++ //If we were not able to reset the device, return the relevant error code. ++ if(err) ++ err = -ENODEV; ++ } ++ //Otherwise, indicate that there's no such device. ++ else { ++ err = -ENODEV; ++ } ++ ++ return err ? err : count; ++ ++} ++static DRIVER_ATTR_WO(reset_device); + + static void pcistub_exit(void) + { +@@ -1473,6 +1742,8 @@ static void pcistub_exit(void) + &driver_attr_irq_handlers); + driver_remove_file(&xen_pcibk_pci_driver.driver, + &driver_attr_irq_handler_state); ++ driver_remove_file(&xen_pcibk_pci_driver.driver, ++ &driver_attr_reset_device); + pci_unregister_driver(&xen_pcibk_pci_driver); + } + +@@ -1569,6 +1840,9 @@ static int __init pcistub_init(void) + if (!err) + err = driver_create_file(&xen_pcibk_pci_driver.driver, + &driver_attr_irq_handler_state); ++ if (!err) ++ err = driver_create_file(&xen_pcibk_pci_driver.driver, ++ &driver_attr_reset_device); + if (err) + pcistub_exit(); + diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-pv-video-quirks/openxt-pv-video-quirks.scc b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-pv-video-quirks/openxt-pv-video-quirks.scc new file mode 100644 index 0000000000..cc397a94bb --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-pv-video-quirks/openxt-pv-video-quirks.scc @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: MIT +define KFEATURE_DESCRIPTION "Apply OpenXT PV video quirks." +define KFEATURE_COMPATIBILITY all + +# Use maximum absolute width/height dimension for xenkbd to support tablet. +## TODO: determine if this is necessary. +patch xenkbd-tablet-resolution.patch diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-pv-video-quirks/xenkbd-tablet-resolution.patch b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-pv-video-quirks/xenkbd-tablet-resolution.patch new file mode 100644 index 0000000000..75b2500467 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-pv-video-quirks/xenkbd-tablet-resolution.patch @@ -0,0 +1,59 @@ +################################################################################ +SHORT DESCRIPTION: +################################################################################ +Use large dimensions for tablet absolute coordinates. + +################################################################################ +LONG DESCRIPTION: +################################################################################ + +################################################################################ +CHANGELOG +################################################################################ +Original author: unknown +Port to 3.18: Eric Chanudet +Port to 4.14: Richard Turner + +################################################################################ +REMOVAL +################################################################################ +? + +################################################################################ +UPSTREAM PLAN +################################################################################ +None. + +################################################################################ +INTERNAL DEPENDENCIES +################################################################################ +None. + +################################################################################ +PATCHES +################################################################################ +--- a/drivers/input/misc/xen-kbdfront.c ++++ b/drivers/input/misc/xen-kbdfront.c +@@ -303,9 +303,9 @@ static int xenkbd_probe(struct xenbus_de + if (abs) { + __set_bit(EV_ABS, ptr->evbit); + input_set_abs_params(ptr, ABS_X, 0, +- ptr_size[KPARAM_X], 0, 0); ++ XENFB_TABLET_WIDTH, 0, 0); + input_set_abs_params(ptr, ABS_Y, 0, +- ptr_size[KPARAM_Y], 0, 0); ++ XENFB_TABLET_HEIGHT, 0, 0); + } else { + input_set_capability(ptr, EV_REL, REL_X); + input_set_capability(ptr, EV_REL, REL_Y); +--- a/include/xen/interface/io/fbif.h ++++ b/include/xen/interface/io/fbif.h +@@ -137,6 +137,8 @@ struct xenfb_page { + #ifdef __KERNEL__ + #define XENFB_WIDTH 800 + #define XENFB_HEIGHT 600 ++#define XENFB_TABLET_WIDTH 32767 ++#define XENFB_TABLET_HEIGHT 32767 + #define XENFB_DEPTH 32 + #endif + diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-serial-quirks/dont-suspend-xen-serial-port.patch b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-serial-quirks/dont-suspend-xen-serial-port.patch new file mode 100644 index 0000000000..0f0736922e --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-serial-quirks/dont-suspend-xen-serial-port.patch @@ -0,0 +1,53 @@ +################################################################################ +SHORT DESCRIPTION: +################################################################################ +Remove PNP_DISABLE capability for serial port on 0x3f8 as Xen uses it and will +disable it when going to S3. + +################################################################################ +LONG DESCRIPTION: +################################################################################ +Disables the functionality to evaluate ACPI _DIS method on serial 0x3f8 which +is used by Xen logging. Fixes S3 for machines with PNP serial port. Xen is +supposed to disable the serial port as it uses it. + +################################################################################ +CHANGELOG +################################################################################ +Original Author: unknown +Port to 3.18: Eric Chanudet +Port to 4.14: Richard Turner +Port to 4.19: Richard Turner + +################################################################################ +REMOVAL +################################################################################ +Without this work-around, S3 is known to fail on machines with PNP serial ports. +(Optiplex 980 for example). + +################################################################################ +UPSTREAM PLAN +################################################################################ +None. + +################################################################################ +INTERNAL DEPENDENCIES +################################################################################ +None. + +################################################################################ +PATCHES +################################################################################ +--- a/drivers/tty/serial/8250/8250_pnp.c ++++ b/drivers/tty/serial/8250/8250_pnp.c +@@ -454,6 +454,10 @@ serial_pnp_probe(struct pnp_dev *dev, co + } else if (pnp_port_valid(dev, 0)) { + uart.port.iobase = pnp_port_start(dev, 0); + uart.port.iotype = UPIO_PORT; ++ /* Xen uses port 3f8 for logging, turn off ability to disable it as it breaks suspend */ ++ if (uart.port.iobase == 0x3f8) { ++ dev->capabilities &= ~PNP_DISABLE; ++ } + } else if (pnp_mem_valid(dev, 0)) { + uart.port.mapbase = pnp_mem_start(dev, 0); + uart.port.iotype = UPIO_MEM; diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-serial-quirks/hvc-kgdb-fix.patch b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-serial-quirks/hvc-kgdb-fix.patch new file mode 100644 index 0000000000..212ce7573d --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-serial-quirks/hvc-kgdb-fix.patch @@ -0,0 +1,91 @@ +################################################################################ +SHORT DESCRIPTION: +################################################################################ +Fall back to cons_ops if tty->driver_data is not ready. + +################################################################################ +LONG DESCRIPTION: +################################################################################ +See http://lists.xen.org/archives/html/xen-devel/2012-06/msg00484.html. + +Use tty->driver_data, if available or fall back to using cons_ops. + +################################################################################ +CHANGELOG +################################################################################ +Original Author: Ben Guthro +Port to 3.18: Eric Chanudet +Port to 4.14: Richard Turner +Port to 4.19: Richard Turner + +################################################################################ +REMOVAL +################################################################################ +Until fixed upstream. + +################################################################################ +UPSTREAM PLAN +################################################################################ +None. + +################################################################################ +INTERNAL DEPENDENCIES +################################################################################ +None, allows kgdb over hvc for debugging. + +################################################################################ +PATCHES +################################################################################ +--- a/drivers/tty/hvc/hvc_console.c ++++ b/drivers/tty/hvc/hvc_console.c +@@ -861,11 +861,13 @@ static int hvc_poll_init(struct tty_driv + static int hvc_poll_get_char(struct tty_driver *driver, int line) + { + struct tty_struct *tty = driver->ttys[0]; +- struct hvc_struct *hp = tty->driver_data; ++ struct hvc_struct *hp = tty ? tty->driver_data : NULL; ++ struct hv_ops *ops = (hp && hp->ops) ? hp->ops : cons_ops[last_hvc]; ++ uint32_t vtno = hp ? hp->vtermno : vtermnos[last_hvc]; + int n; + char ch; + +- n = hp->ops->get_chars(hp->vtermno, &ch, 1); ++ n = ops->get_chars(vtno, &ch, 1); + + if (n <= 0) + return NO_POLL_CHAR; +@@ -876,11 +878,14 @@ static int hvc_poll_get_char(struct tty_ + static void hvc_poll_put_char(struct tty_driver *driver, int line, char ch) + { + struct tty_struct *tty = driver->ttys[0]; +- struct hvc_struct *hp = tty->driver_data; ++ struct hvc_struct *hp = tty ? tty->driver_data : NULL; ++ struct hv_ops *ops = (hp && hp->ops) ? hp->ops : cons_ops[last_hvc]; ++ uint32_t vtno = hp ? hp->vtermno : vtermnos[last_hvc]; ++ + int n; + + do { +- n = hp->ops->put_chars(hp->vtermno, &ch, 1); ++ n = ops->put_chars(vtno, &ch, 1); + } while (n <= 0); + } + #endif +--- a/kernel/debug/debug_core.c ++++ b/kernel/debug/debug_core.c +@@ -653,6 +653,7 @@ return_normal: + kgdb_roundup_cpus(); + #endif + ++#ifndef CONFIG_XEN + /* + * Wait for the other CPUs to be notified and be waiting for us: + */ +@@ -663,6 +664,7 @@ return_normal: + udelay(1000); + if (!time_left) + pr_crit("Timed out waiting for secondary CPUs.\n"); ++#endif + + /* + * At this point the primary processor is completely diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-serial-quirks/intel-amt-support.patch b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-serial-quirks/intel-amt-support.patch new file mode 100644 index 0000000000..387fb1f628 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-serial-quirks/intel-amt-support.patch @@ -0,0 +1,45 @@ +--- a/drivers/net/ethernet/intel/e1000/e1000_hw.c ++++ b/drivers/net/ethernet/intel/e1000/e1000_hw.c +@@ -4278,7 +4278,7 @@ static void e1000_init_rx_addrs(struct e + /* Setup the receive address. */ + e_dbg("Programming MAC Address into RAR[0]\n"); + +- e1000_rar_set(hw, hw->mac_addr, 0); ++ e1000_rar_set(hw, hw->perm_mac_addr, 0); + + rar_num = E1000_RAR_ENTRIES; + +--- a/drivers/net/ethernet/intel/e1000/e1000_main.c ++++ b/drivers/net/ethernet/intel/e1000/e1000_main.c +@@ -2216,7 +2216,7 @@ static int e1000_set_mac(struct net_devi + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); + memcpy(hw->mac_addr, addr->sa_data, netdev->addr_len); + +- e1000_rar_set(hw, hw->mac_addr, 0); ++ e1000_rar_set(hw, hw->mac_addr, E1000_RAR_ENTRIES - 2); + + if (hw->mac_type == e1000_82542_rev2_0) + e1000_leave_82542_rst(adapter); +--- a/drivers/net/ethernet/intel/e1000e/mac.c ++++ b/drivers/net/ethernet/intel/e1000e/mac.c +@@ -117,7 +117,7 @@ void e1000e_init_rx_addrs(struct e1000_h + /* Setup the receive address */ + e_dbg("Programming MAC Address into RAR[0]\n"); + +- hw->mac.ops.rar_set(hw, hw->mac.addr, 0); ++ hw->mac.ops.rar_set(hw, hw->mac.perm_addr, 0); + + /* Zero out the other (rar_entry_count - 1) receive addresses */ + e_dbg("Clearing RAR[1-%u]\n", rar_count - 1); +--- a/drivers/net/ethernet/intel/e1000e/netdev.c ++++ b/drivers/net/ethernet/intel/e1000e/netdev.c +@@ -4764,7 +4764,8 @@ static int e1000_set_mac(struct net_devi + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); + memcpy(adapter->hw.mac.addr, addr->sa_data, netdev->addr_len); + +- hw->mac.ops.rar_set(&adapter->hw, adapter->hw.mac.addr, 0); ++ hw->mac.ops.rar_set(&adapter->hw, adapter->hw.mac.addr, ++ adapter->hw.mac.rar_entry_count - 2); + + if (adapter->flags & FLAG_RESET_OVERWRITES_LAA) { + /* activate the work around */ diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-serial-quirks/openxt-serial-quirks.scc b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-serial-quirks/openxt-serial-quirks.scc new file mode 100644 index 0000000000..d193f093e8 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-serial-quirks/openxt-serial-quirks.scc @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: MIT +define KFEATURE_DESCRIPTION "Apply OpenXT serial device quirks." +define KFEATURE_COMPATIBILITY all + +# Remove PNP_DISABLE cap for UART port with iobase 0x3f8. +patch dont-suspend-xen-serial-port.patch + +# Fix AMT support for e1000, e1000e devices? +patch intel-amt-support.patch + +# Fallback to cons_ops if tty->driver_data is not ready. +patch hvc-kgdb-fix.patch diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-service-vms/disable-csum-xennet.patch b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-service-vms/disable-csum-xennet.patch new file mode 100644 index 0000000000..31f11e3972 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-service-vms/disable-csum-xennet.patch @@ -0,0 +1,67 @@ +################################################################################ +SHORT DESCRIPTION: +################################################################################ +Do not offload ip checksum to guests. + +################################################################################ +LONG DESCRIPTION: +################################################################################ +Disable NETIF_F_IP_CSUM_BIT & NETIF_F_IPV6_CSUM_BIT for xen-netdev. + +################################################################################ +CHANGELOG +################################################################################ +Original Author: unknown +Port to 3.18: Eric Chanudet +Port to 4.14: Richard Turner +Port to 4.19: Richard Turner + +################################################################################ +REMOVAL +################################################################################ +"feature-no-csum-offload" and "feature-ipv6-csum-offload" Xenstore nodes can be +used as well to enable the feature or not, this patch only forces it to off in +any case. + +################################################################################ +UPSTREAM PLAN +################################################################################ +None, could be dealt with at guest creation and be configurable. + +################################################################################ +INTERNAL DEPENDENCIES +################################################################################ +Unknown. + +################################################################################ +PATCHES +################################################################################ +--- a/drivers/net/xen-netback/interface.c ++++ b/drivers/net/xen-netback/interface.c +@@ -532,9 +532,7 @@ struct xenvif *xenvif_alloc(struct devic + INIT_LIST_HEAD(&vif->fe_mcast_addr); + + dev->netdev_ops = &xenvif_netdev_ops; +- dev->hw_features = NETIF_F_SG | +- NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | +- NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_FRAGLIST; ++ dev->hw_features = NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6; + dev->features = dev->hw_features | NETIF_F_RXCSUM; + dev->ethtool_ops = &xenvif_ethtool_ops; + +--- a/drivers/net/xen-netfront.c ++++ b/drivers/net/xen-netfront.c +@@ -1313,11 +1313,8 @@ static struct net_device *xennet_create_ + + netdev->netdev_ops = &xennet_netdev_ops; + +- netdev->features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM | +- NETIF_F_GSO_ROBUST; +- netdev->hw_features = NETIF_F_SG | +- NETIF_F_IPV6_CSUM | +- NETIF_F_TSO | NETIF_F_TSO6; ++ netdev->features = NETIF_F_RXCSUM | NETIF_F_GSO_ROBUST; ++ netdev->hw_features = NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6; + + /* + * Assume that all hw features are available for now. This set diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-service-vms/netback-skip-frontend-wait-during-shutdown.patch b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-service-vms/netback-skip-frontend-wait-during-shutdown.patch new file mode 100644 index 0000000000..0d7119a3cf --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-service-vms/netback-skip-frontend-wait-during-shutdown.patch @@ -0,0 +1,87 @@ +################################################################################ +SHORT DESCRIPTION: +################################################################################ +Close backend without waiting the frontend driver. + +################################################################################ +LONG DESCRIPTION: +################################################################################ +Force the put_device() instead of waiting for the frontend driver to close +properly. This is a work-around as some backend may run in service VM that +could eventually wait for frontend in dead guests prohibiting dom0 to +shutdown, sleep or hibernate. + +################################################################################ +CHANGELOG +################################################################################ +Original author: unknown +Port to 3.18: Eric Chanudet +Port to 4.14: Richard Turner +Port to 4.19: Richard Turner + +################################################################################ +REMOVAL +################################################################################ +Removal will require a better approach to deal with troubled guests sharing a +backend with a service VM. + +################################################################################ +UPSTREAM PLAN +################################################################################ +None, this is an OpenXT work-around. + +################################################################################ +INTERNAL DEPENDENCIES +################################################################################ +Service VM PV backend. + +################################################################################ +PATCHES +################################################################################ +--- a/drivers/xen/xenbus/xenbus.h ++++ b/drivers/xen/xenbus/xenbus.h +@@ -133,6 +133,13 @@ int xenbus_read_otherend_details(struct + + void xenbus_ring_ops_init(void); + ++static inline bool xenbus_dev_is_vif(const struct xenbus_device *dev) ++{ ++ return (dev && ++ (!strcmp("vif", dev->devicetype) || ++ !strcmp("vwif", dev->devicetype))); ++} ++ + int xenbus_dev_request_and_reply(struct xsd_sockmsg *msg, void *par); + void xenbus_dev_queue_reply(struct xb_req_data *req); + +--- a/drivers/xen/xenbus/xenbus_probe_backend.c ++++ b/drivers/xen/xenbus/xenbus_probe_backend.c +@@ -192,6 +192,19 @@ static void frontend_changed(struct xenb + xenbus_otherend_changed(watch, path, token, 0); + } + ++void xenbus_dev_shutdown_backend(struct device *_dev) ++{ ++ struct xenbus_device *dev = to_xenbus_device(_dev); ++ ++ get_device(&dev->dev); ++ if (system_state > SYSTEM_RUNNING && !xenbus_dev_is_vif(dev)) ++ DPRINTK("%s: skipping wait for frontend to close\n", ++ dev->nodename); ++ else ++ xenbus_dev_shutdown(_dev); ++ put_device(&dev->dev); ++} ++ + static struct xen_bus_type xenbus_backend = { + .root = "backend", + .levels = 3, /* backend/type// */ +@@ -205,7 +218,7 @@ static struct xen_bus_type xenbus_backen + .uevent = xenbus_uevent_backend, + .probe = xenbus_dev_probe, + .remove = xenbus_dev_remove, +- .shutdown = xenbus_dev_shutdown, ++ .shutdown = xenbus_dev_shutdown_backend, + .dev_groups = xenbus_dev_groups, + }, + }; diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-service-vms/netfront-support-backend-relocate.patch b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-service-vms/netfront-support-backend-relocate.patch new file mode 100644 index 0000000000..7d78cd262f --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-service-vms/netfront-support-backend-relocate.patch @@ -0,0 +1,70 @@ +################################################################################ +SHORT DESCRIPTION: +################################################################################ +Treat a vanishing backend as a request to close the front-end. + +################################################################################ +LONG DESCRIPTION: +################################################################################ +Usual scenario would be dom0 releaving netback responsibility to NDVM ending up +to rmmod its backend module. Xenstore node would disapear and Xenbus switch to +unknown state. We might as well consider it, on the frontend side (e.g, in +UIVM) to be a close request, so the guest will be able to reconnect with the +new backend in the service VM. + +################################################################################ +CHANGELOG +################################################################################ +Original author: Steve Meisner +Port to 3.18: Eric Chanudet +Modified by: Troy Crosley +Port to 4.14: Richard Turner +Port to 4.19: Richard Turner + +################################################################################ +REMOVAL +################################################################################ +Supporting backend relocation would require some work in the current protocol +without this patch. + +################################################################################ +UPSTREAM PLAN +################################################################################ +None, this is an OpenXT work-around. + +################################################################################ +INTERNAL DEPENDENCIES +################################################################################ +Service VM PV backend. + +################################################################################ +PATCHES +################################################################################ +--- a/drivers/net/xen-netfront.c ++++ b/drivers/net/xen-netfront.c +@@ -2022,11 +2022,24 @@ static void netback_changed(struct xenbu + case XenbusStateInitialised: + case XenbusStateReconfiguring: + case XenbusStateReconfigured: ++ break; ++ + case XenbusStateUnknown: ++ /* if the backend vanishes from xenstore, close frontend */ ++ if (!xenbus_exists(XBT_NIL, dev->otherend, "") && ++ (dev->state != XenbusStateUnknown)) { ++ dev_warn(&dev->dev, ++ "backend vanished, closing frontend\n"); ++ if (dev->state != XenbusStateClosed) ++ xenbus_frontend_closed(dev); ++ netif_carrier_off(np->netdev); ++ } + break; + + case XenbusStateInitWait: +- if (dev->state != XenbusStateInitialising) ++ /* allow reconnect if our state is either initialising, or closed */ ++ if (dev->state != XenbusStateInitialising && ++ dev->state != XenbusStateClosed) + break; + if (xennet_connect(netdev) != 0) + break; diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-service-vms/openxt-service-vms.scc b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-service-vms/openxt-service-vms.scc new file mode 100644 index 0000000000..7854476caf --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-service-vms/openxt-service-vms.scc @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: MIT +define KFEATURE_DESCRIPTION "Apply OpenXT service VMs fixes." +define KFEATURE_COMPATIBILITY all + +# Do not offload ip checksum to guests. +patch disable-csum-xennet.patch + +# Close backend without waiting the frontend closure. +patch netback-skip-frontend-wait-during-shutdown.patch + +# Manage chained backend relying on xenstore-watches. +patch xenbus-move-otherend-watches-on-relocate.patch + +# Handle vanishing backend as request to close the frontend. +patch netfront-support-backend-relocate.patch + +# Do not add tty0 to prefereed consoles. +patch xenpv-no-tty0-as-default-console.patch diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-service-vms/xenbus-move-otherend-watches-on-relocate.patch b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-service-vms/xenbus-move-otherend-watches-on-relocate.patch new file mode 100644 index 0000000000..ad10423a1b --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-service-vms/xenbus-move-otherend-watches-on-relocate.patch @@ -0,0 +1,110 @@ +################################################################################ +SHORT DESCRIPTION: +################################################################################ +Manage chained backend relocation. + +################################################################################ +LONG DESCRIPTION: +################################################################################ +Tweak xenbus state machine to manage chained back-end domains to be restarted +without loosing the xenstore watches. + +################################################################################ +CHANGELOG +################################################################################ +Original author: unknown +Port to 3.18: Eric Chanudet +Port to 4.14: Richard Turner +Port to 4.19: Richard Turner + +################################################################################ +REMOVAL +################################################################################ +Disagregation with PV drivers need this patch to run smoothly unless some +refactoring is done to adapt the state machine. + +################################################################################ +UPSTREAM PLAN +################################################################################ +None. + +################################################################################ +INTERNAL DEPENDENCIES +################################################################################ +Complements netfront-support-backend-relocate.patch. +Required for service VM network disagregation. + +################################################################################ +PATCHES +################################################################################ +--- a/drivers/xen/xenbus/xenbus_probe.c ++++ b/drivers/xen/xenbus/xenbus_probe.c +@@ -554,12 +554,36 @@ static int strsep_len(const char *str, c + return (len == 0) ? i : -ERANGE; + } + ++static int move_otherend(struct xenbus_device *dev) ++{ ++ int err; ++ ++ /* Only move netdevs. */ ++ if (!dev || !dev->dev.driver) ++ return 0; ++ if (!xenbus_dev_is_vif(dev)) ++ return 0; ++ ++ DPRINTK("xenbus %s: otherend possibly changed location;\ ++ renegotiating connection\n", dev->nodename); ++ err = talk_to_otherend(dev); ++ if (err) { ++ DPRINTK("talk_to_otherend on %s failed.\n", dev->nodename); ++ return err; ++ } ++ err = watch_otherend(dev); ++ if (err) ++ DPRINTK("watch_otherend on %s failed.\n", dev->nodename); ++ ++ return err; ++} ++ + void xenbus_dev_changed(const char *node, struct xen_bus_type *bus) + { +- int exists, rootlen; ++ int exists, nodelen, rootlen; + struct xenbus_device *dev; + char type[XEN_BUS_ID_SIZE]; +- const char *p, *root; ++ const char *p, *root, *ending; + + if (char_count(node, '/') < 2) + return; +@@ -571,6 +595,7 @@ void xenbus_dev_changed(const char *node + } + + /* backend//... or device//... */ ++ nodelen = strnlen(node, INT_MAX); + p = strchr(node, '/') + 1; + snprintf(type, XEN_BUS_ID_SIZE, "%.*s", (int)strcspn(p, "/"), p); + type[XEN_BUS_ID_SIZE-1] = '\0'; +@@ -582,12 +607,20 @@ void xenbus_dev_changed(const char *node + if (!root) + return; + ++ ending = kasprintf(GFP_KERNEL, "%.*s", nodelen - rootlen, node + rootlen); ++ if (!ending) ++ return; + dev = xenbus_device_find(root, &bus->bus); + if (!dev) + xenbus_probe_node(bus, type, root); +- else ++ else { ++ if (!strcmp(ending, "/backend") || !strcmp(ending, "/frontend")) ++ /* reconfigure xenstore watches if backend/frontend node pointer has changed */ ++ move_otherend(dev); + put_device(&dev->dev); ++ } + ++ kfree(ending); + kfree(root); + } + EXPORT_SYMBOL_GPL(xenbus_dev_changed); diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-service-vms/xenpv-no-tty0-as-default-console.patch b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-service-vms/xenpv-no-tty0-as-default-console.patch new file mode 100644 index 0000000000..825bfe9231 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-service-vms/xenpv-no-tty0-as-default-console.patch @@ -0,0 +1,54 @@ +################################################################################ +SHORT DESCRIPTION: +################################################################################ +Do not add tty0 to the preferred consoles. + +################################################################################ +LONG DESCRIPTION: +################################################################################ +Preferred consoles behavior used to not affect dom0 until: +47b02f4c621c x86/xen: add tty0 and hvc0 as preferred consoles for dom0 +71dc05635983 x86/Xen: further refine add_preferred_console() invocations + +Since these changes, PV guests will always output on tty0 and hvc0 regardless +of console= parameter. This makes some noise at boot. + +None of the PV kernels used in OpenXT rely on that, yet silencing the loglevel +is not desired as the serial output is often used to debug boot issues. This +change temporarily does _not_ add tty0 as a default preferred console. + +console_set_on_cmdline is not usable at this stage unfortunately since the +cmdline has not been parsed yet. + +################################################################################ +REMOVAL +################################################################################ +Once a better alternative is available, this patch should be removed. + +################################################################################ +UPSTREAM PLAN +################################################################################ +None. + +################################################################################ +INTERNAL DEPENDENCIES +################################################################################ +None. + +################################################################################ +PATCHES +################################################################################ +--- a/arch/x86/xen/enlighten_pv.c ++++ b/arch/x86/xen/enlighten_pv.c +@@ -1406,11 +1406,7 @@ asmlinkage __visible void __init xen_sta + #endif + } + +- if (!boot_params.screen_info.orig_video_isVGA) +- add_preferred_console("tty", 0, NULL); + add_preferred_console("hvc", 0, NULL); +- if (boot_params.screen_info.orig_video_isVGA) +- add_preferred_console("tty", 0, NULL); + + #ifdef CONFIG_PCI + /* PCI BIOS service won't work from a PV guest. */ diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-tpm/openxt-tpm.scc b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-tpm/openxt-tpm.scc new file mode 100644 index 0000000000..3827919d70 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-tpm/openxt-tpm.scc @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: MIT +define KFEATURE_DESCRIPTION "Apply OpenXT TPM chardev quirks." +define KFEATURE_COMPATIBILITY all + +# Log the TPM TCG vendor-id, device-id and revision-id. +patch tpm-log-didvid.patch + +# Work-around TPM iomem region being marked as RAM under specific circumstances. +# TODO: determine if this is still necessary (32-bit kernel no longer supported). +patch tpm-tis-force-ioremap.patch diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-tpm/tpm-log-didvid.patch b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-tpm/tpm-log-didvid.patch new file mode 100644 index 0000000000..0c829341bc --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-tpm/tpm-log-didvid.patch @@ -0,0 +1,51 @@ +################################################################################ +SHORT DESCRIPTION: +################################################################################ +Trace the TPM TCG vendor ID. + +################################################################################ +LONG DESCRIPTION: +################################################################################ +Output the TPM TCG vendor ID with the device ID and the revision ID to identify +the TPM device in use on the log output. + +################################################################################ +CHANGELOG +################################################################################ +Original author: Ross Philipson +Port to 3.18: Eric Chanudet +Port to 4.14: Richard Turner +Port to 4.19: Richard Turner + +################################################################################ +REMOVAL +################################################################################ +This patch is for debugging purposes and can be safely removed. + +################################################################################ +UPSTREAM PLAN +################################################################################ +None. + +################################################################################ +INTERNAL DEPENDENCIES +################################################################################ +None. + +################################################################################ +PATCHES +################################################################################ +--- a/drivers/char/tpm/tpm_tis_core.c ++++ b/drivers/char/tpm/tpm_tis_core.c +@@ -899,9 +899,9 @@ int tpm_tis_core_init(struct device *dev + if (rc < 0) + goto out_err; + +- dev_info(dev, "%s TPM (device-id 0x%X, rev-id %d)\n", ++ dev_info(dev, "%s TPM (vendor-id 0x%X device-id 0x%X, rev-id %d)\n", + (chip->flags & TPM_CHIP_FLAG_TPM2) ? "2.0" : "1.2", +- vendor >> 16, rid); ++ vendor & 0xffff, vendor >> 16, rid); + + probe = probe_itpm(chip); + if (probe < 0) { diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-tpm/tpm-tis-force-ioremap.patch b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-tpm/tpm-tis-force-ioremap.patch new file mode 100644 index 0000000000..8b5b2dca51 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-tpm/tpm-tis-force-ioremap.patch @@ -0,0 +1,25 @@ +--- a/drivers/char/tpm/tpm_tis.c ++++ b/drivers/char/tpm/tpm_tis.c +@@ -226,8 +226,20 @@ static int tpm_tis_init(struct device *d + return -ENOMEM; + + phy->iobase = devm_ioremap_resource(dev, &tpm_info->res); +- if (IS_ERR(phy->iobase)) +- return PTR_ERR(phy->iobase); ++ if (IS_ERR(phy->iobase)) { ++ /* This region is only reported in one of the SSDT, not the ++ * e820. On a system using a 32bit kernel and enough memory, ++ * the kernel might end up making this region a RAM buffer, ++ * disabling the TPM. ++ * devm_ioremap() was used (prior 4.6?), avoiding the ++ * devm_request_mem_region() that currently fails under the ++ * mentioned circumstances. Fallback to that until a better fix ++ * is found. ++ */ ++ phy->iobase = devm_ioremap(dev, tpm_info->res.start, resource_size(&tpm_info->res)); ++ if (IS_ERR(phy->iobase)) ++ return PTR_ERR(phy->iobase); ++ } + + if (interrupts) + irq = tpm_info->irq; diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-usbback/openxt-usbback.scc b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-usbback/openxt-usbback.scc new file mode 100644 index 0000000000..62402d529f --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-usbback/openxt-usbback.scc @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: MIT +define KFEATURE_DESCRIPTION "Add OpenXT paravirtualized usb backend driver." +define KFEATURE_COMPATIBILITY all + +patch usbback-base.patch diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-usbback/usbback-base.patch b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-usbback/usbback-base.patch new file mode 100644 index 0000000000..9a0806ea13 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-usbback/usbback-base.patch @@ -0,0 +1,4440 @@ +################################################################################ +SHORT DESCRIPTION: +################################################################################ +USB backend driver. + +################################################################################ +LONG DESCRIPTION: +################################################################################ +Para-virtualized USB backend driver... + +################################################################################ +CHANGELOG +################################################################################ +Original author: unknown +Contributor: Ross Philipson +Port to 3.18: Eric Chanudet +Port to 4.14: Richard Turner +Port to 4.19: Richard Turner + +################################################################################ +REMOVAL +################################################################################ +Allow and control access to USB devices from guests using the para-virtualized +tools. + +################################################################################ +UPSTREAM PLAN +################################################################################ +None. + +################################################################################ +INTERNAL DEPENDENCIES +################################################################################ +Guest pv-tools. +UIVM interface. +Toolstack in general. + +################################################################################ +PATCHES +################################################################################ +--- a/drivers/scsi/sr.c ++++ b/drivers/scsi/sr.c +@@ -269,6 +269,15 @@ static unsigned int sr_check_events(stru + if (!(clearing & DISK_EVENT_MEDIA_CHANGE)) + return events; + do_tur: ++ /* ++ * Earlier GET_EVENT_STATUS_NOTIFICATION and TUR did not agree ++ * for a couple of times in a row. We rely on TUR only for this ++ * likely broken device, to prevent generating incorrect media ++ * changed events for every open(). ++ */ ++ if (cd->ignore_get_event) ++ events &= ~DISK_EVENT_MEDIA_CHANGE; ++ + /* let's see whether the media is there with TUR */ + last_present = cd->media_present; + ret = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr); +@@ -281,8 +290,19 @@ do_tur: + cd->media_present = scsi_status_is_good(ret) || + (scsi_sense_valid(&sshdr) && sshdr.asc != 0x3a); + +- if (last_present != cd->media_present) ++ if (last_present != cd->media_present) { + cd->device->changed = 1; ++ } else if (events & DISK_EVENT_MEDIA_CHANGE) { ++ if (cd->tur_mismatch > 8) { ++ printk("%s: GET_EVENT and TUR disagree continuously, " ++ "suppress GET_EVENT events\n", cd->cdi.name); ++ cd->ignore_get_event = true; ++ } else { ++ cd->tur_mismatch++; ++ } ++ } else if (!cd->ignore_get_event && cd->tur_mismatch > 0) { ++ cd->tur_mismatch = 0; ++ } + + if (cd->device->changed) { + events |= DISK_EVENT_MEDIA_CHANGE; +--- a/drivers/usb/Kconfig ++++ b/drivers/usb/Kconfig +@@ -109,6 +109,17 @@ source "drivers/usb/image/Kconfig" + + source "drivers/usb/usbip/Kconfig" + ++comment "Xen USB devices" ++ ++config XEN_USBDEV_BACKEND ++ tristate "Xen usb-device backend driver" ++ depends on XEN_BACKEND ++ default XEN_BACKEND ++ help ++ The usb-device backend driver allows the kernel to export its ++ usb devices to other guests via a high-performance shared-memory ++ interface. ++ + endif + + source "drivers/usb/cdns3/Kconfig" +--- a/drivers/usb/Makefile ++++ b/drivers/usb/Makefile +@@ -66,3 +66,5 @@ obj-$(CONFIG_USBIP_CORE) += usbip/ + obj-$(CONFIG_TYPEC) += typec/ + + obj-$(CONFIG_USB_ROLE_SWITCH) += roles/ ++ ++obj-$(CONFIG_XEN_USBDEV_BACKEND) += xen-usbback/ +--- a/drivers/usb/core/Makefile ++++ b/drivers/usb/core/Makefile +@@ -7,6 +7,7 @@ usbcore-y := usb.o hub.o hcd.o urb.o mes + usbcore-y += config.o file.o buffer.o sysfs.o endpoint.o + usbcore-y += devio.o notify.o generic.o quirks.o devices.o + usbcore-y += phy.o port.o ++usbcore-y += dusb.o + + usbcore-$(CONFIG_OF) += of.o + usbcore-$(CONFIG_USB_PCI) += hcd-pci.o +--- /dev/null ++++ b/drivers/usb/core/dusb.c +@@ -0,0 +1,169 @@ ++/*****************************************************************************/ ++ ++/* ++ * dusb.c -- Direct communication with USB devices. ++ * ++ * Copyright (C) 1999-2000 Thomas Sailer (sailer@ife.ee.ethz.ch) ++ * Copyright (C) 2008-2012 Virtual Computer Inc ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * ++ * Derived from usb/core/devio.c ++ * ++ */ ++ ++/*****************************************************************************/ ++ ++#include ++#include ++#include ++#include ++#ifdef CONFIG_PROC_FS ++#include ++#include ++#endif ++#include /* for usbcore internals */ ++ ++#include "usb.h" ++ ++#if 1 ++#define dprintk(args...) ++#define dprintk2(args...) ++#else ++#define dprintk printk ++#define dprintk2 printk ++#endif ++ ++#define lock_kernel() ++#define unlock_kernel() ++ ++static int __match_minor(struct device *dev, const void *data) ++{ ++ const int minor = *((const int *)data); ++ ++ if (dev->devt == MKDEV(USB_DEVICE_MAJOR, minor)) ++ return 1; ++ return 0; ++} ++ ++static struct usb_device *usbdev_lookup_by_minor(int minor) ++{ ++ struct device *dev; ++ ++ dev = bus_find_device(&usb_bus_type, NULL, &minor, __match_minor); ++ if (!dev) ++ return NULL; ++ ++ return container_of(dev, struct usb_device, dev); ++} ++ ++struct usb_device *dusb_open(unsigned bus, unsigned device) ++{ ++ int minor = ((bus - 1) * 128) + (device - 1); ++ struct usb_device *dev = NULL; ++ ++ dev = usbdev_lookup_by_minor(minor); ++ if (NULL == dev) ++ goto out; ++ ++ usb_lock_device(dev); ++ ++ usb_get_dev(dev); ++ put_device(&dev->dev); ++ usb_unlock_device(dev); ++ ++out: ++ ++ return dev; ++} ++EXPORT_SYMBOL(dusb_open); ++ ++void dusb_close(struct usb_device *dev) ++{ ++ usb_lock_device(dev); ++ ++ /* ++ * Resetting the device will make sure it gets reprobed and ++ * another device driver can claim it. ++ */ ++ usb_reset_device(dev); ++ usb_unlock_device(dev); ++ ++ usb_put_dev(dev); ++} ++EXPORT_SYMBOL(dusb_close); ++ ++int dusb_set_configuration(struct usb_device *dev, int configuration) ++{ ++ return usb_set_configuration(dev, configuration); ++} ++EXPORT_SYMBOL(dusb_set_configuration); ++ ++void dusb_flush_endpoint(struct usb_device *udev, struct usb_host_endpoint *ep) ++{ ++ usb_hcd_flush_endpoint(udev, ep); ++} ++EXPORT_SYMBOL(dusb_flush_endpoint); ++ ++int dusb_reenumerate(unsigned bus, unsigned device) ++{ ++ int minor = ((bus - 1) * 128) + (device - 1); ++ struct usb_device *udev = NULL; ++ ++ udev = usbdev_lookup_by_minor(minor); ++ if (udev) { ++ printk("Forcing re-enumeration of %s - %s\n", ++ udev->product, udev->manufacturer); ++ usb_device_reenumerate(udev); ++ put_device(&udev->dev); ++ } ++ ++ return (udev != NULL); ++} ++EXPORT_SYMBOL(dusb_reenumerate); ++ ++int dusb_dev_running(struct usb_device *udev) ++{ ++ struct usb_hcd *hcd = bus_to_hcd(udev->bus); ++ ++ return (hcd ? HCD_RH_RUNNING(hcd) : 0); ++} ++EXPORT_SYMBOL(dusb_dev_running); ++ ++static int dusb_hcd_speed_super(struct usb_hcd *hcd) ++{ ++ return (hcd->driver->flags & HCD_USB3); ++} ++ ++static int dusb_hcd_speed_high(struct usb_hcd *hcd) ++{ ++ return (hcd->driver->flags & HCD_USB2); ++} ++ ++static int dusb_hcd_speed(struct usb_hcd *hcd) ++{ ++ return (dusb_hcd_speed_super(hcd) ? USB_SPEED_SUPER : ++ (dusb_hcd_speed_high(hcd) ? USB_SPEED_HIGH : USB_SPEED_LOW)); ++} ++ ++int dusb_dev_controller_speed(struct usb_device *udev) ++{ ++ struct usb_hcd *hcd = bus_to_hcd(udev->bus); ++ ++ return (hcd ? dusb_hcd_speed(hcd) : 0); ++} ++EXPORT_SYMBOL(dusb_dev_controller_speed); ++ +--- a/drivers/usb/core/hub.c ++++ b/drivers/usb/core/hub.c +@@ -1005,6 +1005,15 @@ int usb_remove_device(struct usb_device + return 0; + } + ++void usb_device_reenumerate(struct usb_device *udev) ++{ ++ struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent); ++ int port1 = udev->portnum; ++ ++ hub_port_logical_disconnect(hub, port1); ++} ++EXPORT_SYMBOL(usb_device_reenumerate); ++ + enum hub_activation_type { + HUB_INIT, HUB_INIT2, HUB_INIT3, /* INITs must come first */ + HUB_POST_RESET, HUB_RESUME, HUB_RESET_RESUME, +@@ -5907,7 +5916,7 @@ int usb_reset_device(struct usb_device * + struct usb_driver *drv; + int unbind = 0; + +- if (cintf->dev.driver) { ++ if (cintf && cintf->dev.driver) { + drv = to_usb_driver(cintf->dev.driver); + if (drv->pre_reset && drv->post_reset) + unbind = (drv->pre_reset)(cintf); +@@ -5928,7 +5937,12 @@ int usb_reset_device(struct usb_device * + for (i = config->desc.bNumInterfaces - 1; i >= 0; --i) { + struct usb_interface *cintf = config->interface[i]; + struct usb_driver *drv; +- int rebind = cintf->needs_binding; ++ int rebind; ++ ++ if (!cintf) ++ continue; ++ ++ rebind = cintf->needs_binding; + + if (!rebind && cintf->dev.driver) { + drv = to_usb_driver(cintf->dev.driver); +--- a/drivers/usb/host/xhci-pci.c ++++ b/drivers/usb/host/xhci-pci.c +@@ -289,6 +289,11 @@ static void xhci_pci_quirks(struct devic + if (xhci->quirks & XHCI_RESET_ON_RESUME) + xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, + "QUIRK: Resetting on resume"); ++ ++ /* The use of BEI causes deadlock with VUSB ++ * FIXME: BEI should be made to work with VUSB! ++ */ ++ xhci->quirks |= XHCI_AVOID_BEI; + } + + #ifdef CONFIG_ACPI +--- /dev/null ++++ b/drivers/usb/xen-usbback/Makefile +@@ -0,0 +1,3 @@ ++obj-$(CONFIG_XEN_USBDEV_BACKEND) := usbbk.o ++ ++usbbk-y := usbback.o xenbus.o interface.o vusb.o buffers.o +--- /dev/null ++++ b/drivers/usb/xen-usbback/buffers.c +@@ -0,0 +1,422 @@ ++/****************************************************************************** ++ * usbback/buffers.c ++ * ++ * Routines for managing virtual usb devices. ++ * ++ * Copyright (c) Citrix Systems Inc. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (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 "common.h" ++ ++#if (DUMP_URB_SZ > 0) ++void dump(uint8_t *buffer, int len) ++{ ++ int i; ++ ++ if ((buffer != NULL) && (len > 0)) { ++ printk(" data: "); ++ for (i=0; (i < len) && (i < DUMP_URB_SZ); i++) { ++ printk("%02x ", buffer[i]); ++ if ((i & 0x3f) == 0x20) ++ printk("\n"); ++ } ++ printk("\n"); ++ } else { ++ printk(" data: none\n"); ++ } ++} ++ ++static void dump_iso_urb(struct urb *urb) ++{ ++ struct usb_iso_packet_descriptor *desc = urb->iso_frame_desc; ++ uint8_t *buffer = urb->transfer_buffer; ++ int i; ++ ++ for (i=0; inumber_of_packets; i++) ++ dump(&buffer[desc[i].offset], desc[i].length); ++} ++#endif ++ ++/* ++ * Move data between DomU and URB buffers ++ */ ++static int copy_first_chunk(uint8_t *dst, uint8_t *src, int offset, int remaining) ++{ ++ int len; ++ ++ if ((PAGE_SIZE - offset) > remaining) ++ len = remaining; ++ else ++ len = (PAGE_SIZE - offset); ++ ++ memcpy(dst, src, len); ++ ++ return len; ++} ++ ++static int copy_chunk(uint8_t *dst, uint8_t *src, int remaining) ++{ ++ return copy_first_chunk(dst, src, 0, remaining); ++} ++ ++static void copy_out_req(pending_req_t *pending_req) ++{ ++ uint8_t *dst, *src; ++ int i, len, remaining, nr_pages; ++ ++ remaining = pending_req->urb->transfer_buffer_length; ++ nr_pages = data_pages(pending_req); ++ ++ if (!nr_pages) ++ return; ++ ++ /* copy first seg */ ++ dst = pending_req->urb->transfer_buffer; ++ src = (uint8_t *)vaddr(pending_req, 0) + pending_req->offset; ++ ++ len = copy_first_chunk(dst, src, pending_req->offset, remaining); ++ ++ dst += len; ++ remaining -= len; ++ ++ /* copy remaining segs */ ++ for (i = 1; i < nr_pages; i++) { ++ src = (uint8_t *)vaddr(pending_req, i); ++ ++ len = copy_chunk(dst, src, remaining); ++ ++ dst += len; ++ remaining -= len; ++ } ++ ++#if (DUMP_URB_SZ > 0) ++ if (usbback_debug_lvl() >= LOG_LVL_DUMP) ++ dump(pending_req->urb->transfer_buffer, ++ pending_req->urb->transfer_buffer_length); ++#endif ++} ++ ++static int setup_sg(struct scatterlist *sg, uint8_t *src, int offset, int remaining) ++{ ++ int len; ++ ++ if ((PAGE_SIZE - offset) > remaining) ++ len = remaining; ++ else ++ len = (PAGE_SIZE - offset); ++ ++ debug_print(LOG_LVL_DEBUG, " sg: ptr %p len %d\n", src + offset, len); ++ ++ sg_set_buf(sg, src + offset, len); ++ ++#if (DUMP_URB_SZ > 0) ++ if (usbback_debug_lvl() >= LOG_LVL_DUMP) ++ dump(src + offset, len); ++#endif ++ ++ return len; ++} ++ ++static void setup_sgs(pending_req_t *pending_req, int iso) ++{ ++ struct urb *urb = pending_req->urb; ++ int i, len, remaining; ++ uint8_t *src; ++ ++ remaining = urb->transfer_buffer_length; ++ if (iso) ++ urb->num_sgs = data_pages(pending_req) - 1; ++ else ++ urb->num_sgs = data_pages(pending_req); ++ ++ sg_init_table(urb->sg, urb->num_sgs); ++ ++ /* setup first seg */ ++ if (iso) ++ src = (uint8_t *)vaddr(pending_req, 1); ++ else ++ src = (uint8_t *)vaddr(pending_req, 0); ++ ++ len = setup_sg(&urb->sg[0], src, pending_req->offset, remaining); ++ debug_print(LOG_LVL_DEBUG, "%d: sg: off %d len %d\n", ++ 0, pending_req->offset, len); ++ ++ remaining -= len; ++ ++ /* setup remaining segs */ ++ for (i = 1; i < urb->num_sgs; i++) { ++ if (iso) ++ src = (uint8_t *)vaddr(pending_req, i + 1); ++ else ++ src = (uint8_t *)vaddr(pending_req, i); ++ ++ len = setup_sg(&urb->sg[i], src, 0, remaining); ++ debug_print(LOG_LVL_DEBUG, "%d: sg: off %d len %d\n", ++ i, 0, len); ++ ++ remaining -= len; ++ } ++} ++ ++static int copy_out_iso_descriptors(pending_req_t *pending_req) ++{ ++ struct usb_iso_packet_descriptor *desc; ++ usbif_iso_packet_info_t *info; ++ int i, length = 0; ++ ++ if (!data_pages(pending_req)) ++ return (length); ++ ++ /* copy ISO packet descriptors */ ++ info = (usbif_iso_packet_info_t *)vaddr(pending_req, 0); ++ desc = pending_req->urb->iso_frame_desc; ++ ++ for (i=0; inr_packets; i++) { ++ int end = info[i].offset + info[i].length; ++ ++ debug_print(LOG_LVL_DEBUG, " %d: iso desc: off %d len %d\n", ++ i, info[i].offset, info[i].length); ++ desc[i].offset = info[i].offset; ++ desc[i].length = info[i].length; ++ desc[i].actual_length = 0; ++ desc[i].status = 0; ++ ++ if (end > length) ++ length = end; ++ } ++ ++ return (length); ++} ++ ++static int copy_out_iso(pending_req_t *pending_req) ++{ ++ uint8_t *dst, *src; ++ int i, len, remaining, nr_pages; ++ ++ remaining = pending_req->urb->transfer_buffer_length; ++ nr_pages = data_pages(pending_req); ++ ++ if (nr_pages < 2) ++ return (0); ++ ++ /* copy first seg */ ++ dst = pending_req->urb->transfer_buffer; ++ src = (uint8_t *)vaddr(pending_req, 1) + pending_req->offset; ++ ++ len = copy_first_chunk(dst, src, pending_req->offset, remaining); ++ ++ dst += len; ++ remaining -= len; ++ ++ /* copy remaining segs */ ++ for (i = 2; i < nr_pages; i++) { ++ src = (uint8_t *)vaddr(pending_req, i); ++ ++ len = copy_chunk(dst, src, remaining); ++ ++ dst += len; ++ remaining -= len; ++ } ++ ++#if (DUMP_URB_SZ > 0) ++ if (usbback_debug_lvl() >= LOG_LVL_DUMP) ++ dump_iso_urb(pending_req->urb); ++#endif ++ return (0); ++} ++ ++int copy_out(pending_req_t *pending_req) ++{ ++ struct urb *urb = pending_req->urb; ++ ++ if (pending_req->type == USBIF_T_ISOC) { ++ if (copy_out_iso_descriptors(pending_req) > ++ pending_req->urb->transfer_buffer_length) ++ return (-EINVAL); ++ ++ if (urb->sg) ++ setup_sgs(pending_req, 1); ++ else if (!pending_req->direction_in) ++ copy_out_iso(pending_req); ++ } else { ++ if (urb->sg) ++ setup_sgs(pending_req, 0); ++ else if (!pending_req->direction_in) ++ copy_out_req(pending_req); ++ } ++ ++ return (0); ++} ++ ++static void copy_in_req(pending_req_t *pending_req) ++{ ++ uint8_t *dst, *src; ++ int i, len, remaining, nr_pages; ++ ++ remaining = pending_req->urb->actual_length; ++ nr_pages = data_pages(pending_req); ++ ++ if (!nr_pages) ++ return; ++ ++ /* copy first seg */ ++ dst = (uint8_t *)vaddr(pending_req, 0) + pending_req->offset; ++ src = pending_req->urb->transfer_buffer; ++ ++ len = copy_first_chunk(dst, src, pending_req->offset, remaining); ++ ++ src += len; ++ remaining -= len; ++ ++ /* copy remaining segs */ ++ for (i = 1; i < nr_pages; i++) { ++ dst = (uint8_t *)vaddr(pending_req, i); ++ ++ len = copy_chunk(dst, src, remaining); ++ ++ src += len; ++ remaining -= len; ++ } ++ ++#if (DUMP_URB_SZ > 0) ++ if (usbback_debug_lvl() >= LOG_LVL_DUMP) ++ dump(pending_req->urb->transfer_buffer, ++ pending_req->urb->actual_length); ++#endif ++} ++ ++static void cleanup_sgs(pending_req_t *pending_req) ++{ ++ struct urb *urb = pending_req->urb; ++ int i; ++ ++ debug_print(LOG_LVL_DEBUG, "sgs: total %d mapped %d\n", ++ urb->num_sgs, urb->num_mapped_sgs); ++ ++ for (i = 0; i < urb->num_sgs; i++) { ++ struct scatterlist *sg = &urb->sg[i]; ++ ++ debug_print(LOG_LVL_DEBUG, " %d: ptr %p len %d\n", ++ i, sg_virt(sg), sg->length); ++ ++#if (DUMP_URB_SZ > 0) ++ if (usbback_debug_lvl() >= LOG_LVL_DUMP) ++ dump(sg_virt(sg), sg->length); ++#endif ++ } ++} ++ ++static int copy_in_iso_descriptors(pending_req_t *pending_req) ++{ ++ struct usb_iso_packet_descriptor *desc; ++ usbif_iso_packet_info_t *info; ++ int i, length = 0; ++ ++ if (!data_pages(pending_req)) ++ return (length); ++ ++ /* copy ISO packet descriptors */ ++ info = (usbif_iso_packet_info_t *)vaddr(pending_req, 0); ++ desc = pending_req->urb->iso_frame_desc; ++ ++ debug_print(LOG_LVL_DEBUG, "iso descs: %d info %p desc %p\n", ++ pending_req->nr_packets, info, desc); ++ ++ for (i=0; inr_packets; i++) { ++ int end = desc[i].offset + desc[i].actual_length; ++ ++ if (pending_req->direction_in) { ++ info[i].length = desc[i].actual_length; ++ info[i].status = get_usb_status(desc[i].status); ++ } ++ debug_print(LOG_LVL_DEBUG, ++ " %d: iso desc: off %d len %d status %d\n", ++ i, desc[i].offset, desc[i].length, desc[i].status); ++ ++ if (end > length) ++ length = end; ++ } ++ ++ return (length); ++} ++ ++static void copy_in_iso(pending_req_t *pending_req, int remaining) ++{ ++ uint8_t *dst, *src; ++ int i, len, nr_pages; ++ ++ nr_pages = data_pages(pending_req); ++ ++ if (data_pages(pending_req) < 2) ++ return; ++ ++ /* copy first seg */ ++ dst = (uint8_t *)vaddr(pending_req, 1) + pending_req->offset; ++ src = pending_req->urb->transfer_buffer; ++ ++ len = copy_first_chunk(dst, src, pending_req->offset, remaining); ++ ++ src += len; ++ remaining -= len; ++ ++ /* copy remaining segs */ ++ for (i = 2; i < nr_pages; i++) { ++ dst = (uint8_t *)vaddr(pending_req, i); ++ ++ len = copy_chunk(dst, src, remaining); ++ ++ src += len; ++ remaining -= len; ++ } ++ ++#if (DUMP_URB_SZ > 0) ++ if (usbback_debug_lvl() >= LOG_LVL_DUMP) ++ dump_iso_urb(pending_req->urb); ++#endif ++} ++ ++void copy_in(pending_req_t *pending_req) ++{ ++ struct urb *urb = pending_req->urb; ++ ++ if (pending_req->type == USBIF_T_ISOC) { ++ int remaining = copy_in_iso_descriptors(pending_req); ++ ++ if (urb->sg) ++ cleanup_sgs(pending_req); ++ else if (pending_req->direction_in) ++ copy_in_iso(pending_req, remaining); ++ } else { ++ if (urb->sg) ++ cleanup_sgs(pending_req); ++ else if (pending_req->direction_in) ++ copy_in_req(pending_req); ++ } ++} ++ +--- /dev/null ++++ b/drivers/usb/xen-usbback/common.h +@@ -0,0 +1,362 @@ ++/* ++ * Copyright (c) Citrix Systems Inc. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (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. ++ */ ++ ++#ifndef __USBIF__BACKEND__COMMON_H__ ++#define __USBIF__BACKEND__COMMON_H__ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#define DPRINTK(_f, _a...) \ ++ pr_debug("(file=%s, line=%d) " _f, \ ++ __FILE__ , __LINE__ , ## _a ) ++ ++#undef VUSB_MANAGE_INTERFACES ++#define USBBK_TIMEOUT (15 * HZ) ++#define USBBCK_NRPACKS 1024 ++#define DUMP_URB_SZ 32 ++#undef DEBUG_CHECKS ++#define USBBCK_VERSION 3 ++#define USBBCK_MAX_URB_SZ (10 * 1024 * 1024) ++ ++static inline int usbif_request_type(usbif_request_t *req) ++{ ++ return (req->type); ++} ++ ++static inline int usbif_request_dir_in(usbif_request_t *req) ++{ ++ return ((req->endpoint & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN); ++} ++ ++static inline int usbif_request_endpoint_num(usbif_request_t *req) ++{ ++ return (req->endpoint & USB_ENDPOINT_NUMBER_MASK); ++} ++ ++static inline int usbif_request_offset(usbif_request_t *req) ++{ ++ return (req->offset); ++} ++ ++static inline int usbif_request_shortok(usbif_request_t *req) ++{ ++ return (req->flags & USBIF_F_SHORTOK); ++} ++ ++static inline int usbif_request_reset(usbif_request_t *req) ++{ ++ return ((req->flags & USBIF_F_RESET) || (req->type == USBIF_T_RESET)); ++} ++ ++static inline int usbif_request_cycle_port(usbif_request_t *req) ++{ ++ return (req->flags & USBIF_F_CYCLE_PORT); ++} ++ ++static inline int usbif_request_abort_pipe(usbif_request_t *req) ++{ ++ return (req->type == USBIF_T_ABORT_PIPE); ++} ++ ++static inline int usbif_request_get_frame(usbif_request_t *req) ++{ ++ return (req->type == USBIF_T_GET_FRAME); ++} ++ ++static inline int usbif_request_get_speed(usbif_request_t *req) ++{ ++ return (req->type == USBIF_T_GET_SPEED); ++} ++ ++static inline int usbif_request_cancel(usbif_request_t *req) ++{ ++ return (req->type == USBIF_T_CANCEL); ++} ++ ++static inline int usbif_request_type_valid(usbif_request_t *req) ++{ ++ return (req->type <= USBIF_T_MAX); ++} ++ ++static inline int usbif_request_asap(usbif_request_t *req) ++{ ++ return (req->flags & USBIF_F_ASAP); ++} ++ ++static inline int usbif_request_indirect(usbif_request_t *req) ++{ ++ return (req->flags & USBIF_F_INDIRECT); ++} ++ ++static inline int usbif_request_timeout(usbif_request_t *req) ++{ ++ return ((usbif_request_type(req) == USBIF_T_CNTRL) || ++ !usbif_request_dir_in(req)); ++} ++ ++struct usbif_st; ++ ++struct vusb { ++ /* what the domain refers to this vusb as */ ++ usbif_vdev_t handle; ++ unsigned bus; ++ unsigned device; ++ struct usb_device *usbdev; ++ struct usb_anchor anchor; ++ int initted; ++ int active; ++ int canceling_requests; ++ /* maximum sgs supported by HCD this device is attached to */ ++ unsigned max_sgs; ++ int hcd_speed; ++ /* device is allowed to suspend */ ++ int autosuspend : 1; ++ /* copy unaligned transfers? */ ++ int copy_unaligned : 1; ++ struct kref kref; ++}; ++#define KREF_TO_VUSB(d) container_of(d, struct vusb, kref) ++ ++struct backend_info; ++ ++typedef struct usbif_stats_st { ++ int st_oo_req; ++ int st_in_req; ++ int st_out_req; ++ ++ int st_error; ++ int st_reset; ++ ++ int st_in_bandwidth; ++ int st_out_bandwidth; ++ ++ int st_cntrl_req; ++ int st_isoc_req; ++ int st_bulk_req; ++ int st_int_req; ++ int st_ind_req; ++} usbif_stats_t; ++ ++typedef struct usbif_st { ++ /* Unique identifier for this interface. */ ++ domid_t domid; ++ unsigned int handle; ++ /* Physical parameters of the comms window. */ ++ unsigned int irq; ++ /* Comms information. */ ++ enum usbif_protocol usb_protocol; ++ usbif_back_rings_t usb_rings; ++ void *usb_ring_addr; ++ /* The VUSB attached to this interface. */ ++ struct vusb vusb; ++ /* Back pointer to the backend_info. */ ++ struct backend_info *be; ++ /* Private fields. */ ++ spinlock_t usb_ring_lock; ++ atomic_t refcnt; ++ ++ wait_queue_head_t wq; ++ struct task_struct *xenusbd; ++ unsigned int waiting_reqs; ++ ++ /* statistics */ ++ unsigned long st_print; ++ usbif_stats_t stats; ++ ++ wait_queue_head_t waiting_to_free; ++} usbif_t; ++ ++static inline struct usbif_st *usbif_from_vusb(struct vusb *vusb) ++{ ++ return container_of(vusb, struct usbif_st, vusb); ++} ++ ++struct backend_info ++{ ++ struct xenbus_device *dev; ++ usbif_t *usbif; ++ ++ struct xenbus_watch backend_watch; ++ struct xenbus_watch autosuspend_watch; ++ unsigned bus; ++ unsigned device; ++}; ++ ++typedef struct { ++ struct list_head free_list; ++ struct page *page; ++ grant_handle_t grant_handle; ++} pending_segment_t; ++ ++/* ++ * Each outstanding request that we've passed to the lower device layers has a ++ * 'pending_req' allocated to it. When the associated URB completes, the specified domain has a ++ * response queued for it, with the saved 'id' passed back. ++ */ ++typedef struct { ++ usbif_t *usbif; ++ u64 id; ++ int type; ++ int direction_in; ++ uint16_t offset; ++ int nr_pages; ++ int nr_packets; ++ struct list_head free_list; ++ struct list_head to_free_list; ++ struct urb *urb; ++#ifdef USBBK_TIMEOUT ++ struct timer_list timer; ++#endif ++ pending_segment_t *pending_segment[USBIF_MAX_SEGMENTS_PER_REQUEST]; ++ int pending_segments; ++#ifdef INDIRECT_SEGMENTS ++ pending_segment_t **pending_indirect_segment; ++ int pending_indirect_segments; ++ usbif_indirect_request_t *indirect_req[USBIF_MAX_SEGMENTS_PER_REQUEST]; ++#endif ++} pending_req_t; ++ ++static inline int is_indirect(pending_req_t *req) ++{ ++ return (req->pending_indirect_segments > 0); ++} ++ ++static inline unsigned long vaddr_base(pending_req_t *req, int seg) ++{ ++ unsigned long pfn = page_to_pfn(req->pending_segment[seg]->page); ++ return (unsigned long)pfn_to_kaddr(pfn); ++} ++ ++static inline unsigned long vaddr(pending_req_t *req, int seg) ++{ ++#ifdef INDIRECT_SEGMENTS ++ struct page *page = is_indirect(req) ? ++ req->pending_indirect_segment[seg]->page : ++ req->pending_segment[seg]->page; ++ unsigned long pfn = page_to_pfn(page); ++ return (unsigned long)pfn_to_kaddr(pfn); ++#else ++ return vaddr_base(req, seg); ++#endif ++} ++ ++static inline int data_pages(pending_req_t *req) ++{ ++ return (is_indirect(req) ? ++ req->pending_indirect_segments : ++ req->nr_pages); ++} ++ ++ ++usbif_t *usbif_alloc(domid_t domid); ++void usbif_kill_xenusbd(usbif_t *usbif); ++void usbif_disconnect(usbif_t *usbif, struct xenbus_device *dev); ++void usbif_free(usbif_t *usbif); ++int usbif_map(usbif_t *usbif, grant_ref_t shpage_ref, unsigned int evtchn); ++ ++int get_usb_status(int status); ++ ++#define usbif_get(_b) (atomic_inc(&(_b)->refcnt)) ++#define usbif_put(_b) \ ++ do { \ ++ if (atomic_dec_and_test(&(_b)->refcnt)) \ ++ wake_up(&(_b)->waiting_to_free);\ ++ } while (0) ++ ++static inline int vusb_connected(struct vusb *vusb) ++{ ++ return (vusb->usbdev != NULL); ++} ++int vusb_init(void); ++int vusb_create(usbif_t *usbif, usbif_vdev_t vdevice, unsigned bus, ++ unsigned device); ++void vusb_free(struct vusb *vusb); ++int vusb_setup_urb(struct vusb *vusb, usbif_request_t *req, struct urb *urb); ++static inline int vusb_canceling_requests(struct vusb *vusb) ++{ ++ return (vusb->canceling_requests == 1); ++} ++int vusb_reset_device(struct vusb *vusb); ++void vusb_flush(struct vusb *vusb); ++int vusb_flush_endpoint(struct vusb *vusb, usbif_request_t *req); ++int vusb_get_speed(struct vusb *vusb); ++void vusb_free_coherent(struct vusb *vusb, struct urb *urb); ++void *vusb_alloc_coherent(struct vusb *vusb, size_t size, dma_addr_t *dma); ++void vusb_cycle_port(struct vusb *vusb); ++ ++/* vusb power management methods */ ++void vusb_pm_autosuspend_control(struct vusb *vusb, int enable); ++ ++void usbif_interface_init(void); ++ ++int usbif_xenbus_init(void); ++ ++irqreturn_t usbif_be_int(int irq, void *dev_id); ++int usbif_schedule(void *arg); ++ ++int usbback_barrier(struct xenbus_transaction xbt, ++ struct backend_info *be, int state); ++int usbback_suspend(usbif_t *usbif, int suspended); ++ ++unsigned int usbback_debug_lvl(void); ++ ++#define LOG_LVL_ERROR 0 ++#define LOG_LVL_INFO 1 ++#define LOG_LVL_DEBUG 2 ++#define LOG_LVL_DUMP 3 ++ ++#define debug_print(l, _f, ...) \ ++ do { if (usbback_debug_lvl() >= (l)) printk((_f), ##__VA_ARGS__); } while(0) ++ ++static inline unsigned int buffer_pages(unsigned int length) ++{ ++ return ((length + PAGE_SIZE - 1) >> PAGE_SHIFT); ++} ++ ++/* buffer handling routines */ ++int copy_out(pending_req_t *pending_req); ++void copy_in(pending_req_t *pending_req); ++ ++void dump(uint8_t *buffer, int len); ++ ++#endif /* __USBIF__BACKEND__COMMON_H__ */ +--- /dev/null ++++ b/drivers/usb/xen-usbback/interface.c +@@ -0,0 +1,165 @@ ++/****************************************************************************** ++ * ++ * usb device interface management. ++ * ++ * Copyright (c) 2004, Keir Fraser ++ * Copyright (c) 2008-2012, Virtual Computer Inc. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (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 ++ ++#include "common.h" ++ ++static struct kmem_cache *usbif_cachep; ++ ++usbif_t *usbif_alloc(domid_t domid) ++{ ++ usbif_t *usbif; ++ ++ usbif = kmem_cache_alloc(usbif_cachep, GFP_KERNEL); ++ if (!usbif) ++ return ERR_PTR(-ENOMEM); ++ ++ memset(usbif, 0, sizeof(*usbif)); ++ usbif->domid = domid; ++ spin_lock_init(&usbif->usb_ring_lock); ++ atomic_set(&usbif->refcnt, 1); ++ init_waitqueue_head(&usbif->wq); ++ usbif->st_print = jiffies; ++ init_waitqueue_head(&usbif->waiting_to_free); ++ ++ return usbif; ++} ++ ++int usbif_map(usbif_t *usbif, grant_ref_t shpage_ref, unsigned int evtchn) ++{ ++ int err; ++ ++ /* Already connected through? */ ++ if (usbif->irq) ++ return 0; ++ ++ debug_print(LOG_LVL_INFO, "Map shared ring, connect event channel\n"); ++ ++ /* Call the xenbus function to map the shared page. It handles the case ++ * where alloc_vm_area is done in a process context that is not init ++ * but only the init_mm tables are updated. Normally a fault would ++ * correct this in other processes but the supsequent hypercall blocks ++ * that fault handling. Therefore in the hypercall it sees the PTE's ++ * not populated. The xenbus routine also tracks the vm area allocation ++ * and the op.handle for cleanup. ++ */ ++ err = xenbus_map_ring_valloc(usbif->be->dev, ++ &shpage_ref, 1, &(usbif->usb_ring_addr)); ++ if (err) ++ return err; ++ ++ switch (usbif->usb_protocol) { ++ case USBIF_PROTOCOL_NATIVE: ++ { ++ struct usbif_sring *sring; ++ sring = (struct usbif_sring *)usbif->usb_ring_addr; ++ BACK_RING_INIT(&usbif->usb_rings.native, sring, PAGE_SIZE); ++ break; ++ } ++ case USBIF_PROTOCOL_X86_32: ++ { ++ struct usbif_x86_32_sring *sring_x86_32; ++ sring_x86_32 = (struct usbif_x86_32_sring *)usbif->usb_ring_addr; ++ BACK_RING_INIT(&usbif->usb_rings.x86_32, sring_x86_32, PAGE_SIZE); ++ break; ++ } ++ case USBIF_PROTOCOL_X86_64: ++ { ++ struct usbif_x86_64_sring *sring_x86_64; ++ sring_x86_64 = (struct usbif_x86_64_sring *)usbif->usb_ring_addr; ++ BACK_RING_INIT(&usbif->usb_rings.x86_64, sring_x86_64, PAGE_SIZE); ++ break; ++ } ++ default: ++ BUG(); ++ } ++ ++ err = bind_interdomain_evtchn_to_irqhandler_lateeoi( ++ usbif->domid, evtchn, usbif_be_int, 0, "usbif-backend", usbif); ++ if (err < 0) ++ { ++ xenbus_unmap_ring_vfree(usbif->be->dev, usbif->usb_ring_addr); ++ usbif->usb_rings.common.sring = NULL; ++ usbif->usb_ring_addr = NULL; ++ return err; ++ } ++ usbif->irq = err; ++ ++ return 0; ++} ++ ++void usbif_kill_xenusbd(usbif_t *usbif) ++{ ++ struct task_struct *xenusbd = xchg(&usbif->xenusbd, NULL); ++ ++ if (xenusbd && !IS_ERR(xenusbd)) ++ kthread_stop(xenusbd); ++} ++ ++void usbif_disconnect(usbif_t *usbif, struct xenbus_device *dev) ++{ ++ debug_print(LOG_LVL_INFO, "Disconnect shared ring and event channel\n"); ++ usbif_kill_xenusbd(usbif); ++ ++ atomic_dec(&usbif->refcnt); ++ wait_event(usbif->waiting_to_free, atomic_read(&usbif->refcnt) == 0); ++ atomic_inc(&usbif->refcnt); ++ ++ if (usbif->irq) { ++ unbind_from_irqhandler(usbif->irq, usbif); ++ usbif->irq = 0; ++ } ++ ++ if (usbif->usb_rings.common.sring) { ++ xenbus_unmap_ring_vfree(dev, usbif->usb_ring_addr); ++ usbif->usb_rings.common.sring = NULL; ++ usbif->usb_ring_addr = NULL; ++ } ++} ++ ++void usbif_free(usbif_t *usbif) ++{ ++ if (!atomic_dec_and_test(&usbif->refcnt)) ++ BUG(); ++ kmem_cache_free(usbif_cachep, usbif); ++} ++ ++void __init usbif_interface_init(void) ++{ ++ usbif_cachep = kmem_cache_create("usbif_cache", sizeof(usbif_t), ++ 0, 0, NULL); ++} +--- /dev/null ++++ b/drivers/usb/xen-usbback/usbback.c +@@ -0,0 +1,1297 @@ ++/****************************************************************************** ++ * ++ * Back-end of the driver for virtual block devices. This portion of the ++ * driver exports a 'unified' block-device interface that can be accessed ++ * by any operating system that implements a compatible front end. A ++ * reference front-end implementation can be found in: ++ * arch/xen/drivers/blkif/frontend ++ * ++ * Back-end of the driver for PV USB. ++ * ++ * Originally based on blkback: ++ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand ++ * Copyright (c) 2005, Christopher Clark ++ * ++ * PV usbback: ++ * Copyright (c) Citrix Systems Inc. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (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. ++ */ ++ ++/* derived from xen/blkback/blkback.c */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "common.h" ++ ++static int usbif_reqs = 128; ++module_param_named(reqs, usbif_reqs, int, 0); ++MODULE_PARM_DESC(reqs, "Number of usbback requests to allocate"); ++ ++/* Run-time switchable: /sys/module/usbback/parameters/ */ ++static unsigned int log_stats = 0; ++static unsigned int debug_lvl = 0; ++module_param(log_stats, int, 0644); ++module_param(debug_lvl, int, 0644); ++ ++unsigned int usbback_debug_lvl(void) ++{ ++ return (debug_lvl); ++} ++static pending_req_t *pending_reqs; ++static struct list_head pending_free; ++static DEFINE_SPINLOCK(pending_free_lock); ++static DECLARE_WAIT_QUEUE_HEAD(pending_free_wq); ++ ++#define USBBACK_INVALID_HANDLE (~0) ++ ++static struct page **pending_pages; ++static pending_segment_t *pending_segments; ++static struct list_head pending_segments_free; ++static int pending_segments_free_cnt; ++ ++static DEFINE_SPINLOCK(pending_to_free_lock); ++static struct list_head pending_to_free; ++static void async_free_reqs(unsigned long); ++static DECLARE_TASKLET(async_free_reqs_task, async_free_reqs, 0); ++ ++static int do_usb_io_op(usbif_t *usbif, unsigned int *eoi_flags); ++static void dispatch_usb_io(usbif_t *usbif, ++ usbif_request_t *req, ++ pending_req_t *pending_req); ++static void make_response(usbif_t *usbif, u64 id, int actual_length, ++ int startframe, int status, int error_count); ++ ++/****************************************************************** ++ * misc small helpers ++ */ ++static int populate_req(pending_req_t *req) ++{ ++ unsigned long flags; ++ int index; ++ ++ req->pending_segments = 0; ++#ifdef INDIRECT_SEGMENTS ++ req->pending_indirect_segments = 0; ++#endif ++ ++ spin_lock_irqsave(&pending_free_lock, flags); ++ if (req->nr_pages > pending_segments_free_cnt) { ++ spin_unlock_irqrestore(&pending_free_lock, flags); ++ debug_print(LOG_LVL_ERROR, ++ "%s not enough segs (%d) need (%d)\n", ++ __FUNCTION__, pending_segments_free_cnt, ++ req->nr_pages); ++ return -1; ++ } ++ ++ for (index=0; indexnr_pages; index++) { ++ pending_segment_t *segment = ++ list_entry(pending_segments_free.next, ++ pending_segment_t, free_list); ++ BUG_ON(!segment); ++ list_del(&segment->free_list); ++ pending_segments_free_cnt--; ++ ++#ifdef DEBUG_CHECKS ++ debug_print(LOG_LVL_DEBUG, ++ "%s %p seg %d (%d) page %p\n", ++ __FUNCTION__, req, index, ++ pending_segments_free_cnt, segment->page); ++#endif ++ req->pending_segment[index] = segment; ++ } ++ req->pending_segments = req->nr_pages; ++ spin_unlock_irqrestore(&pending_free_lock, flags); ++ ++ return 0; ++} ++ ++#ifdef INDIRECT_SEGMENTS ++static int populate_indirect(pending_req_t *req, int segs) ++{ ++ unsigned long flags; ++ int index; ++ ++ spin_lock_irqsave(&pending_free_lock, flags); ++ if (segs > pending_segments_free_cnt) { ++ spin_unlock_irqrestore(&pending_free_lock, flags); ++ debug_print(LOG_LVL_ERROR, ++ "%s not enough segs (%d) need (%d)\n", ++ __FUNCTION__, pending_segments_free_cnt, ++ req->nr_pages); ++ return -1; ++ } ++ ++ for (index=0; indexfree_list); ++ pending_segments_free_cnt--; ++ ++#ifdef DEBUG_CHECKS ++ debug_print(LOG_LVL_DEBUG, ++ "%s req %p seg %d (%d) page %p\n", ++ __FUNCTION__, req, index, pending_segments_free_cnt, ++ segment->page); ++#endif ++ req->pending_indirect_segment[index] = segment; ++ } ++ ++ req->pending_indirect_segments = segs; ++ ++ spin_unlock_irqrestore(&pending_free_lock, flags); ++ ++ return 0; ++} ++#endif ++ ++static pending_req_t* alloc_req(void) ++{ ++ pending_req_t *req = NULL; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&pending_free_lock, flags); ++ if (!list_empty(&pending_free)) { ++ req = list_entry(pending_free.next, pending_req_t, free_list); ++ list_del(&req->free_list); ++ } ++ spin_unlock_irqrestore(&pending_free_lock, flags); ++ ++ debug_print(LOG_LVL_DEBUG, "%s req %p\n", __FUNCTION__, req); ++ ++ return req; ++} ++ ++#ifdef INDIRECT_SEGMENTS ++static void free_indirect_segments(pending_req_t *req) ++{ ++ int index; ++ ++ assert_spin_locked(&pending_free_lock); ++ ++ for (index=0; indexpending_indirect_segments; index++) { ++ pending_segment_t *segment = req->pending_indirect_segment[index]; ++ ++ BUG_ON(!segment); ++ req->pending_indirect_segment[index] = NULL; ++ list_add(&segment->free_list, &pending_segments_free); ++ pending_segments_free_cnt++; ++ ++#ifdef DEBUG_CHECKS ++ debug_print(LOG_LVL_DEBUG, "%s req %p seg %d (%d) page %p\n", ++ __FUNCTION__, req, index, pending_segments_free_cnt, ++ segment->page); ++#endif ++ } ++ ++ kfree(req->pending_indirect_segment); ++ req->pending_indirect_segment = NULL; ++ req->pending_indirect_segments = 0; ++} ++#endif ++ ++static void free_segments(pending_req_t *req) ++{ ++ int index; ++ ++ assert_spin_locked(&pending_free_lock); ++ ++#ifdef INDIRECT_SEGMENTS ++ if (is_indirect(req)) ++ free_indirect_segments(req); ++#endif ++ ++ for (index=0; indexpending_segments; index++) { ++ pending_segment_t *segment = req->pending_segment[index]; ++ ++ BUG_ON(!segment); ++ req->pending_segment[index] = NULL; ++ ++ list_add(&segment->free_list, &pending_segments_free); ++ pending_segments_free_cnt++; ++ ++#ifdef DEBUG_CHECKS ++ debug_print(LOG_LVL_DEBUG, "%s req %p seg %d (%d) page %p\n", ++ __FUNCTION__, req, index, pending_segments_free_cnt, ++ segment->page); ++#endif ++ } ++ req->pending_segments = 0; ++ req->nr_pages = 0; ++} ++ ++static void free_req(pending_req_t *req) ++{ ++ unsigned long flags; ++ int was_empty; ++ struct urb *urb = req->urb; ++ ++ req->urb = NULL; ++ if (urb) { ++ if (urb->transfer_buffer_length) { ++ struct vusb *vusb = &req->usbif->vusb; ++ vusb_free_coherent(vusb, urb); ++ } ++ if (urb->setup_packet) { ++ kfree(urb->setup_packet); ++ urb->setup_packet = NULL; ++ } ++ if (urb->sg) { ++ kfree(urb->sg); ++ urb->sg = NULL; ++ } ++ } ++ req->usbif = NULL; ++ ++ debug_print(LOG_LVL_DEBUG, "%s %p\n", __FUNCTION__, req); ++ ++ spin_lock_irqsave(&pending_free_lock, flags); ++ free_segments(req); ++ was_empty = list_empty(&pending_free); ++ list_add(&req->free_list, &pending_free); ++ spin_unlock_irqrestore(&pending_free_lock, flags); ++ if (was_empty) ++ wake_up(&pending_free_wq); ++} ++ ++static void async_free_reqs(unsigned long data) ++{ ++ struct list_head tmp; ++ pending_req_t *req; ++ struct urb *urb; ++ unsigned long flags; ++ ++ INIT_LIST_HEAD(&tmp); ++ ++ /* Copy to temp list */ ++ spin_lock_irqsave(&pending_to_free_lock, flags); ++ list_splice_init(&pending_to_free, &tmp); ++ spin_unlock_irqrestore(&pending_to_free_lock, flags); ++ ++ /* Run actual free outside of interrupt context */ ++ while (!list_empty(&tmp)) { ++ req = list_entry(tmp.next, pending_req_t, to_free_list); ++ list_del(&req->to_free_list); ++ ++ /* Stash the urb and call the real free_req routine */ ++ urb = req->urb; ++ free_req(req); ++ ++ /* ++ * The urb had its ref count bumped to keep it alive before being queued for ++ * cleanup in this bottom half routine. Dropping that ref here will likely ++ * cleanup and release the urb. ++ */ ++ if (urb) ++ usb_put_urb(urb); ++ } ++} ++ ++#ifdef INDIRECT_SEGMENTS ++static void fast_flush_area_indirect(pending_req_t *req) ++{ ++ struct gnttab_unmap_grant_ref *unmap; ++ unsigned int i, invcount = 0; ++ grant_handle_t *handle; ++ pending_segment_t *indirect_seg; ++ struct page **pages; ++ int ret; ++ ++ debug_print(LOG_LVL_DEBUG, "%s Flushing %d indirect segs!\n", ++ __FUNCTION__, req->pending_indirect_segments); ++ ++ unmap = kmalloc(sizeof(struct gnttab_unmap_grant_ref) * ++ req->pending_indirect_segments, GFP_ATOMIC); ++ if (!unmap) { ++ debug_print(LOG_LVL_ERROR, "%s kmalloc failed for %zu bytes!\n", ++ __FUNCTION__, sizeof(struct gnttab_unmap_grant_ref) * ++ req->pending_indirect_segments); ++ return; ++ } ++ ++ pages = kmalloc_array(req->pending_indirect_segments, sizeof(pages[0]), GFP_ATOMIC); ++ if (!pages) { ++ debug_print(LOG_LVL_ERROR, "%s: req %p malloc %d pages failed\n", ++ __FUNCTION__, req, req->pending_indirect_segments); ++ ret = -1; ++ goto free_unmap; ++ } ++ ++ for (i = 0; i < req->pending_indirect_segments; i++) { ++ indirect_seg = req->pending_indirect_segment[i]; ++ BUG_ON(!indirect_seg); ++ ++ handle = &indirect_seg->grant_handle; ++ if (*handle == USBBACK_INVALID_HANDLE) ++ continue; ++ gnttab_set_unmap_op(&unmap[i], vaddr(req, i), ++ GNTMAP_host_map, *handle); ++ *handle = USBBACK_INVALID_HANDLE; ++ invcount++; ++ pages[i] = indirect_seg->page; ++ } ++ ret = gnttab_unmap_refs(unmap, NULL, pages, invcount); ++ BUG_ON(ret); ++ ++ kfree(pages); ++free_unmap: ++ kfree(unmap); ++} ++#endif ++ ++static void fast_flush_area(pending_req_t *req) ++{ ++ struct gnttab_unmap_grant_ref unmap[USBIF_MAX_SEGMENTS_PER_REQUEST]; ++ unsigned int i, invcount = 0; ++ grant_handle_t *handle; ++ struct page **pages; ++ int ret; ++ ++#ifdef INDIRECT_SEGMENTS ++ if (is_indirect(req)) ++ fast_flush_area_indirect(req); ++#endif ++ ++ pages = kmalloc_array(req->nr_pages, sizeof(pages[0]), GFP_ATOMIC); ++ if (!pages) { ++ debug_print(LOG_LVL_ERROR, "%s: req %p malloc %d pages failed\n", ++ __FUNCTION__, req, req->nr_pages); ++ return; ++ } ++ ++ debug_print(LOG_LVL_DEBUG, "%s Flushing %d segs!\n", ++ __FUNCTION__, req->nr_pages); ++ ++ for (i = 0; i < req->nr_pages; i++) { ++ handle = &req->pending_segment[i]->grant_handle; ++ if (*handle == USBBACK_INVALID_HANDLE) ++ continue; ++ gnttab_set_unmap_op(&unmap[i], vaddr_base(req, i), GNTMAP_host_map, ++ *handle); ++ *handle = USBBACK_INVALID_HANDLE; ++ invcount++; ++ pages[i] = req->pending_segment[i]->page; ++ } ++ ++ ret = gnttab_unmap_refs(unmap, NULL, pages, invcount); ++ BUG_ON(ret); ++ ++ kfree(pages); ++} ++ ++/* ++ * This is our special version of usb_kill_anchored_urbs. Our routine ++ * is a bit like that one except it is used to snipe a single URB. ++ */ ++static void cancel_urb(struct usb_anchor *anchor, u64 cancel_id) ++{ ++ struct urb *victim; ++ bool found = false; ++ ++ spin_lock_irq(&anchor->lock); ++ list_for_each_entry(victim, &anchor->urb_list, anchor_list) { ++ if (((pending_req_t*)victim->context)->id == cancel_id) { ++ usb_get_urb(victim); ++ found = true; ++ break; ++ } ++ } ++ spin_unlock_irq(&anchor->lock); ++ ++ if (!found) ++ return; ++ ++ /* ++ * Now there is an extra ref of the URB. After killing it, drop the ref ++ * count. The docs say the URB cannot be deleted within the kill call. ++ * The ref count will prevent the async cleanup part of the completion ++ * routines from doing this. ++ */ ++ usb_kill_urb(victim); ++ usb_put_urb(victim); ++} ++ ++/****************************************************************** ++ * SCHEDULER FUNCTIONS ++ */ ++ ++static void print_stats(usbif_t *usbif) ++{ ++ usbif_stats_t *stats = &usbif->stats; ++ ++ printk("%s: oo %3d | in %4d (%6d) | out %4d (%6d) | cntrl %4d | " ++ "isoc %4d | bulk %4d | int %4d | ind %4d | err %4d | rst %4d\n", ++ current->comm, stats->st_oo_req, stats->st_in_req, ++ stats->st_in_bandwidth, stats->st_out_req, ++ stats->st_out_bandwidth, stats->st_cntrl_req, ++ stats->st_isoc_req, stats->st_bulk_req, stats->st_int_req, ++ stats->st_ind_req, stats->st_error, stats->st_reset); ++ usbif->st_print = jiffies + msecs_to_jiffies(10 * 1000); ++ memset(&usbif->stats, 0, sizeof(usbif_stats_t)); ++} ++ ++int usbif_schedule(void *arg) ++{ ++ usbif_t *usbif = arg; ++ bool do_eoi; ++ unsigned int eoi_flags = XEN_EOI_FLAG_SPURIOUS; ++ ++ usbif_get(usbif); ++ ++ debug_print(LOG_LVL_INFO, "%s: started\n", current->comm); ++ ++ while (!kthread_should_stop()) { ++ if (try_to_freeze()) ++ continue; ++ ++ wait_event_interruptible( ++ usbif->wq, ++ usbif->waiting_reqs || kthread_should_stop()); ++ wait_event_interruptible( ++ pending_free_wq, ++ !list_empty(&pending_free) || kthread_should_stop()); ++ ++ if (!kthread_should_stop()) { ++ do_eoi = usbif->waiting_reqs; ++ usbif->waiting_reqs = 0; ++ smp_mb(); /* clear flag *before* checking for work */ ++ ++ if (do_usb_io_op(usbif, &eoi_flags)) ++ usbif->waiting_reqs = 1; ++ ++ if (do_eoi && !usbif->waiting_reqs) { ++ xen_irq_lateeoi(usbif->irq, eoi_flags); ++ eoi_flags |= XEN_EOI_FLAG_SPURIOUS; ++ } ++ ++ if (log_stats && time_after(jiffies, usbif->st_print)) ++ print_stats(usbif); ++ } ++ } ++ ++ /* cancel any outstanding URBs */ ++ vusb_flush(&usbif->vusb); ++ ++ if (log_stats) ++ print_stats(usbif); ++ ++ debug_print(LOG_LVL_INFO, "%s: exiting\n", current->comm); ++ ++ usbif_put(usbif); ++ ++ return 0; ++} ++ ++static char *get_usb_statmsg(int status) ++{ ++ static char unkmsg[28]; ++ ++ switch (status) { ++ case 0: ++ return "success"; ++ case -ENOENT: ++ return "unlinked (sync)"; ++ case -EINPROGRESS: ++ return "pending"; ++ case -EPROTO: ++ return "bit stuffing error, timeout, or unknown USB error"; ++ case -EILSEQ: ++ return "CRC mismatch, timeout, or unknown USB error"; ++ case -ETIME: ++ return "timed out"; ++ case -EPIPE: ++ return "endpoint stalled"; ++ case -ECOMM: ++ return "IN buffer overrun"; ++ case -ENOSR: ++ return "OUT buffer underrun"; ++ case -EOVERFLOW: ++ return "too much data"; ++ case -EREMOTEIO: ++ return "short packet detected"; ++ case -ENODEV: ++ case -EHOSTUNREACH: ++ return "device removed"; ++ case -EXDEV: ++ return "partial isochronous transfer"; ++ case -EINVAL: ++ return "invalid argument"; ++ case -ECONNRESET: ++ return "unlinked (async)"; ++ case -ESHUTDOWN: ++ return "device shut down"; ++ default: ++ snprintf(unkmsg, sizeof(unkmsg), "unknown status %d", status); ++ return unkmsg; ++ } ++} ++ ++int get_usb_status(int status) ++{ ++ switch (status) { ++ case 0: ++ /* success */ ++ return USBIF_RSP_OKAY; ++ case -ENOENT: ++ /* unlinked (sync) */ ++ return USBIF_RSP_USB_CANCELED; ++ case -EINPROGRESS: ++ /* pending */ ++ return USBIF_RSP_USB_PENDING; ++ case -EPROTO: ++ /* bit stuffing error, timeout, or unknown USB error */ ++ return USBIF_RSP_USB_PROTO; ++ case -EILSEQ: ++ /* CRC mismatch, timeout, or unknown USB error */ ++ return USBIF_RSP_USB_CRC; ++ case -ETIME: ++ /* timed out */ ++ return USBIF_RSP_USB_TIMEOUT; ++ case -EPIPE: ++ /* endpoint stall */ ++ return USBIF_RSP_USB_STALLED; ++ case -ECOMM: ++ /* IN buffer overrun */ ++ return USBIF_RSP_USB_INBUFF; ++ case -ENOSR: ++ /* OUT buffer underrun */ ++ return USBIF_RSP_USB_OUTBUFF; ++ case -EOVERFLOW: ++ /* too much data */ ++ return USBIF_RSP_USB_OVERFLOW; ++ case -EREMOTEIO: ++ /* short packet detected */ ++ return USBIF_RSP_USB_SHORTPKT; ++ case -ENODEV: ++ /* device removed */ ++ return USBIF_RSP_USB_DEVRMVD; ++ case -EXDEV: ++ /* partial isochronous transfer */ ++ return USBIF_RSP_USB_PARTIAL; ++ case -EMSGSIZE: ++ case -EINVAL: ++ /* invalid argument */ ++ return USBIF_RSP_USB_INVALID; ++ case -ECONNRESET: ++ /* unlinked (async) */ ++ return USBIF_RSP_USB_RESET; ++ case -ESHUTDOWN: ++ /* device shut down */ ++ return USBIF_RSP_USB_SHUTDOWN; ++ default: ++ return USBIF_RSP_USB_UNKNOWN; ++ } ++} ++ ++/* ++ * Handle timeouts ++ */ ++#ifdef USBBK_TIMEOUT ++static void timeout_usb_io_op(struct timer_list *t) ++{ ++ pending_req_t *req = from_timer(req, t, timer); ++ ++ debug_print(LOG_LVL_DEBUG, "%s: urb %p\n", __FUNCTION__, req->urb); ++ ++ usb_unlink_urb(req->urb); ++} ++ ++static void set_timeout(pending_req_t *pending_req) ++{ ++ timer_setup(&pending_req->timer, timeout_usb_io_op, 0); ++ pending_req->timer.expires = jiffies + USBBK_TIMEOUT; ++ add_timer(&pending_req->timer); ++} ++ ++static void cancel_timeout(pending_req_t *pending_req) ++{ ++ if (timer_pending(&pending_req->timer)) ++ del_timer(&pending_req->timer); ++} ++#endif ++ ++/* ++ * COMPLETION CALLBACK ++ */ ++static void end_usb_io_op(struct urb *urb) ++{ ++ pending_req_t *pending_req = (pending_req_t *)urb->context; ++ usbif_t *usbif = pending_req->usbif; ++ int status = vusb_canceling_requests(&usbif->vusb) ? ++ -ECONNRESET : urb->status; ++ unsigned long flags; ++ ++ debug_print(LOG_LVL_INFO, "end id %llu len %d status %d %s\n", ++ pending_req->id, urb->actual_length, status, ++ get_usb_statmsg(status)); ++ ++#ifdef USBBK_TIMEOUT ++ cancel_timeout(pending_req); ++#endif ++ ++ /* ++ * Don't need to unanchor, usb_hcd_giveback_urb has already done it ++ * before calling this completion routine. ++ */ ++ if ((urb->status != -ENODEV) && /* device removed */ ++ (urb->status != -ESHUTDOWN) && /* device disabled */ ++ (urb->status != -EPROTO)) { /* timeout or unknown USB error */ ++ copy_in(pending_req); ++ ++ if (pending_req->direction_in) ++ usbif->stats.st_in_bandwidth += ++ urb->transfer_buffer_length; ++ else ++ usbif->stats.st_out_bandwidth += ++ urb->transfer_buffer_length; ++ } ++ ++ fast_flush_area(pending_req); ++ make_response(usbif, pending_req->id, urb->actual_length, ++ urb->start_frame, get_usb_status(status), ++ (pending_req->type == USBIF_T_ISOC) ? urb->error_count : 0); ++ usbif_put(pending_req->usbif); ++ ++ /* ++ * Schedule async free as it causes an oops on 32bit kernel doing dma frees in ++ * this completion handler with irqs disabled (the WARN_ON(irqs_disabled()) ++ * in dma_free_attrs). We have to bump the ref count on the urb since it will ++ * be released after this completion routine returns. See the code in ++ * hcd.c:usb_hcd_giveback_urb() that call the completion callback. ++ */ ++ urb = usb_get_urb(urb); ++ spin_lock_irqsave(&pending_to_free_lock, flags); ++ list_add_tail(&pending_req->to_free_list, &pending_to_free); ++ spin_unlock_irqrestore(&pending_to_free_lock, flags); ++ tasklet_schedule(&async_free_reqs_task); ++} ++ ++/****************************************************************************** ++ * NOTIFICATION FROM GUEST OS. ++ */ ++ ++static void usbif_notify_work(usbif_t *usbif) ++{ ++ usbif->waiting_reqs = 1; ++ wake_up(&usbif->wq); ++} ++ ++irqreturn_t usbif_be_int(int irq, void *dev_id) ++{ ++ usbif_notify_work(dev_id); ++ return IRQ_HANDLED; ++} ++ ++ ++/****************************************************************** ++ * DOWNWARD CALLS -- These interface with the usb-device layer proper. ++ */ ++ ++static int do_usb_io_op(usbif_t *usbif, unsigned int *eoi_flags) ++{ ++ usbif_back_rings_t *usb_rings = &usbif->usb_rings; ++ usbif_request_t req; ++ pending_req_t *pending_req; ++ RING_IDX rc, rp; ++ int more_to_do = 0; ++ ++ rc = usb_rings->common.req_cons; ++ rp = usb_rings->common.sring->req_prod; ++ rmb(); /* Ensure we see queued requests up to 'rp'. */ ++ ++ while ((rc != rp) && !kthread_should_stop()) { ++ ++ if (RING_REQUEST_CONS_OVERFLOW(&usb_rings->common, rc)) ++ break; ++ ++ /* We have a request, clean the spurious flag. */ ++ *eoi_flags &= ~XEN_EOI_FLAG_SPURIOUS; ++ ++ pending_req = alloc_req(); ++ if (NULL == pending_req) { ++ usbif->stats.st_oo_req++; ++ more_to_do = 1; ++ break; ++ } ++ ++ switch (usbif->usb_protocol) { ++ case USBIF_PROTOCOL_NATIVE: ++ memcpy(&req, RING_GET_REQUEST(&usb_rings->native, rc), sizeof(req)); ++ break; ++ case USBIF_PROTOCOL_X86_32: ++ usbif_get_x86_32_req(&req, RING_GET_REQUEST(&usb_rings->x86_32, rc)); ++ break; ++ case USBIF_PROTOCOL_X86_64: ++ usbif_get_x86_64_req(&req, RING_GET_REQUEST(&usb_rings->x86_64, rc)); ++ break; ++ default: ++ BUG(); ++ } ++ usb_rings->common.req_cons = ++rc; /* before make_response() */ ++ ++ if (!usbif_request_type_valid(&req)) { ++ debug_print(LOG_LVL_ERROR, "%s: type %d not valid\n", ++ __FUNCTION__, usbif_request_type(&req)); ++ make_response(usbif, req.id, 0, 0, USBIF_RSP_ERROR, 0); ++ free_req(pending_req); ++ } else if (usbif_request_reset(&req)) { ++ int ret = vusb_reset_device(&usbif->vusb) ++ ? USBIF_RSP_ERROR : USBIF_RSP_OKAY; ++ ++ make_response(usbif, req.id, 0, 0, ret, 0); ++ free_req(pending_req); ++ } else if (usbif_request_cycle_port(&req)) { ++ vusb_cycle_port(&usbif->vusb); ++ ++ make_response(usbif, req.id, 0, 0, USBIF_RSP_OKAY, 0); ++ free_req(pending_req); ++ } else if (usbif_request_abort_pipe(&req)) { ++ int ret = vusb_flush_endpoint(&usbif->vusb, &req) ++ ? USBIF_RSP_ERROR : USBIF_RSP_OKAY; ++ ++ make_response(usbif, req.id, 0, 0, ret, 0); ++ free_req(pending_req); ++ } else if (usbif_request_get_frame(&req)) { ++ int frame = usb_get_current_frame_number(usbif->vusb.usbdev); ++ ++ if (frame >= 0) ++ make_response(usbif, req.id, 0, frame, 0, 0); ++ else ++ make_response(usbif, req.id, 0, 0, USBIF_RSP_ERROR, 0); ++ free_req(pending_req); ++ } else if (usbif_request_get_speed(&req)) { ++ make_response(usbif, req.id, 0, ++ vusb_get_speed(&usbif->vusb), 0, 0); ++ free_req(pending_req); ++ } else if (usbif_request_cancel(&req)) { ++ cancel_urb(&usbif->vusb.anchor, *((u64*)(&req.u.data[0]))); ++ ++ make_response(usbif, req.id, 0, 0, USBIF_RSP_OKAY, 0); ++ free_req(pending_req); ++ } else ++ dispatch_usb_io(usbif, &req, pending_req); ++ } ++ ++ return more_to_do; ++} ++ ++static struct urb * setup_urb(pending_req_t *pending_req, int length, int* err) ++{ ++ struct vusb *vusb = &pending_req->usbif->vusb; ++ struct urb *urb = usb_alloc_urb(pending_req->nr_packets, GFP_KERNEL); ++ *err=0; ++ ++ pending_req->urb = urb; ++ if (urb == NULL) { ++ *err=1; ++ return (NULL); ++ } ++ ++ /* struct urb is pre zeroed, only init to non zero values */ ++ urb->context = pending_req; ++ urb->complete = end_usb_io_op; ++ urb->number_of_packets = pending_req->nr_packets; ++ ++ if (length > 0) { ++ int pages = buffer_pages(pending_req->offset + length); ++ ++ /* ++ * 1. Linux currently only supports scatter gather for bulk ++ * transfers. ++ * 2. Some controllers can't handle unaligned multipage ++ * DMA transfers. ++ */ ++ if ((vusb->max_sgs > 0) && (pages <= vusb->max_sgs) && ++ ((pages == 1) || (!vusb->copy_unaligned || !pending_req->offset)) && ++ (pending_req->type == USBIF_T_BULK)) { ++ urb->sg = kzalloc(pages * sizeof(struct scatterlist), ++ GFP_KERNEL); ++ if (urb->sg == NULL) { ++ *err=2; ++ return (NULL); ++ } ++ } else { ++ urb->transfer_buffer = vusb_alloc_coherent(vusb, ++ length, &urb->transfer_dma); ++ if (urb->transfer_buffer == NULL) { ++ *err=3; ++ return (NULL); ++ } ++ ++ urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; ++ } ++ urb->transfer_buffer_length = length; ++ } ++ ++ if (unlikely(pending_req->type == USBIF_T_CNTRL)) { ++ urb->setup_packet = ++ kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); ++ if (urb->setup_packet == NULL) { ++ *err=4; ++ return (NULL); ++ } ++ } ++ ++ return (urb); ++} ++ ++static int map_request(pending_req_t *pending_req, int offset, domid_t domid, ++ grant_ref_t *gref, unsigned int nseg, int readonly, ++ int indirect) ++{ ++ struct gnttab_map_grant_ref *map; ++ struct page **pages; ++ int i, ret; ++ ++ BUG_ON(nseg > USBIF_MAX_SEGMENTS_PER_IREQUEST); ++ ++ map = kmalloc(sizeof(struct gnttab_map_grant_ref) * nseg, GFP_KERNEL); ++ if (!map) { ++ debug_print(LOG_LVL_ERROR, "%s: req %p offset %d nseg %d indirect %d\n", ++ __FUNCTION__, pending_req, offset, nseg, indirect); ++ return (-1); ++ } ++ ++ pages = kmalloc_array(nseg, sizeof(pages[0]), GFP_KERNEL); ++ if (!pages) { ++ debug_print(LOG_LVL_ERROR, "%s: req %p offset %d nseg %d indirect %d\n", ++ __FUNCTION__, pending_req, offset, nseg, indirect); ++ ret = -1; ++ goto free_map; ++ } ++ ++ for (i = 0; i < nseg; i++) { ++ uint32_t flags; ++#ifdef INDIRECT_SEGMENTS ++ int page_nr = i + offset; ++ unsigned long virtual_address = indirect ? vaddr(pending_req, page_nr) ++ : vaddr_base(pending_req, page_nr); ++#else ++ unsigned long virtual_address = vaddr_base(pending_req, i); ++#endif ++ ++ if (readonly) ++ flags = (GNTMAP_host_map|GNTMAP_readonly); ++ else ++ flags = GNTMAP_host_map; ++ gnttab_set_map_op(&map[i], virtual_address, flags, gref[i], domid); ++ ++ pages[i] = is_indirect(pending_req) ? ++ pending_req->pending_indirect_segment[page_nr]->page : ++ pending_req->pending_segment[page_nr]->page; ++#ifdef DEBUG_CHECKS ++ debug_print(LOG_LVL_DEBUG, "%s: %d of %d gref %x flags %x vaddr %lx\n", ++ __FUNCTION__, i, nseg, gref[i], flags, virtual_address); ++#endif ++ } ++ ++ ret = gnttab_map_refs(map, NULL, pages, nseg); ++ ++ for (i = 0; i < nseg; i++) { ++ int page_nr = i + offset; ++ ++ if (unlikely(map[i].status != 0)) { ++ debug_print(LOG_LVL_ERROR, ++ "invalid buffer -- could not remap it\n"); ++ map[i].handle = USBBACK_INVALID_HANDLE; ++ ret |= !ret; ++ } ++ ++#ifdef INDIRECT_SEGMENTS ++ if (indirect) ++ pending_req->pending_indirect_segment[page_nr]->grant_handle = map[i].handle; ++ else ++#endif ++ pending_req->pending_segment[i]->grant_handle = map[i].handle; ++ } ++ ++ kfree(pages); ++free_map: ++ kfree(map); ++ ++ return (ret); ++} ++ ++#ifdef INDIRECT_SEGMENTS ++static int setup_indirect(usbif_t *usbif, pending_req_t *pending_req, int segs, int in) ++{ ++ unsigned int indirect_req, mapped_segs = 0; ++ ++ debug_print(LOG_LVL_DEBUG, "%s req %p segs %d\n", __FUNCTION__, pending_req, segs); ++ ++ usbif->stats.st_ind_req++; ++ ++ pending_req->pending_indirect_segment = kmalloc(sizeof(pending_segment_t *) * segs, GFP_KERNEL); ++ if (!pending_req->pending_indirect_segment) { ++ debug_print(LOG_LVL_ERROR, "kmalloc indirect segments failed!\n"); ++ return (-1); ++ } ++ ++ if (populate_indirect(pending_req, segs)) { ++ kfree(pending_req->pending_indirect_segment); ++ pending_req->pending_indirect_segment = NULL; ++ debug_print(LOG_LVL_ERROR, "populate indirect failed!\n"); ++ return (-1); ++ } ++ ++ for (indirect_req=0; indirect_reqnr_pages; indirect_req++) { ++ usbif_indirect_request_t *indirect = ++ (usbif_indirect_request_t *)vaddr_base(pending_req, indirect_req); ++ ++ debug_print(LOG_LVL_DEBUG, "%s req %p indirect %d : %p segs %d\n", ++ __FUNCTION__, pending_req, indirect_req, indirect, ++ indirect->nr_segments); ++#if (DUMP_URB_SZ > 0) ++ if (usbback_debug_lvl() >= LOG_LVL_DUMP) ++ dump((uint8_t *)indirect, PAGE_SIZE); ++#endif ++ ++ pending_req->indirect_req[indirect_req] = indirect; ++ ++ if ((indirect->nr_segments == 0) || ++ (indirect->nr_segments > USBIF_MAX_SEGMENTS_PER_IREQUEST)) { ++ debug_print(LOG_LVL_ERROR, "req bad indirect segs!\n"); ++ return (-1); ++ } ++ ++ if (map_request(pending_req, mapped_segs, ++ usbif->domid, indirect->gref, ++ indirect->nr_segments, in, 1)) { ++ debug_print(LOG_LVL_ERROR, "indirect map failed!\n"); ++ return (-1); ++ } ++ ++ mapped_segs += indirect->nr_segments; ++ } ++ ++ BUG_ON(mapped_segs != segs); ++ ++ return (0); ++} ++#endif ++ ++static void dispatch_usb_io(usbif_t *usbif, usbif_request_t *req, ++ pending_req_t *pending_req) ++{ ++ struct urb *urb; ++ int ret = -EINVAL; ++ int type = usbif_request_type(req); ++ int indirect = usbif_request_indirect(req); ++ int err; ++ ++ debug_print(LOG_LVL_INFO, "start %d id %llu %s type %d end %d" ++ " len %d off %d segs %d flags %x pr %p\n", ++ usbif->vusb.handle, req->id, ++ usbif_request_dir_in(req) ? "IN" : "OUT", ++ type, usbif_request_endpoint_num(req), req->length, ++ usbif_request_offset(req), req->nr_segments, ++ (int)req->flags, pending_req); ++ ++ pending_req->usbif = usbif; ++ pending_req->id = req->id; ++ pending_req->type = req->type; ++ pending_req->direction_in = usbif_request_dir_in(req); ++ pending_req->offset = usbif_request_offset(req); ++ pending_req->nr_pages = req->nr_segments; ++ pending_req->nr_packets = req->nr_packets; ++ pending_req->urb = NULL; ++ ++ if (unlikely(req->length > USBBCK_MAX_URB_SZ)) { ++ debug_print(LOG_LVL_ERROR, ++ "Bad req size %d (%d)\n", ++ req->length, USBBCK_MAX_URB_SZ); ++ goto fail_response; ++ } ++ ++ if (unlikely(pending_req->nr_packets > USBBCK_NRPACKS)) { ++ debug_print(LOG_LVL_ERROR, ++ "Bad number of packets in request (%d : %d)\n", ++ req->nr_packets, USBBCK_NRPACKS); ++ goto fail_response; ++ } ++ ++ if (populate_req(pending_req) < 0) { ++ debug_print(LOG_LVL_ERROR, "Failed populate req\n"); ++ goto fail_response; ++ } ++ ++ urb = setup_urb(pending_req, req->length, &err); ++ if (unlikely(urb == NULL)) { ++ if (printk_ratelimit()) ++ debug_print(LOG_LVL_ERROR, "Failed urb alloc, reason = %d\n", err); ++ goto fail_response; ++ } ++ ++ if (req->length > 0) { ++ /* Check that number of segments is sane. */ ++ int pages = buffer_pages(pending_req->offset + req->length); ++ ++ /* ISO requests have one addition page for the desciptors */ ++ if (type == USBIF_T_ISOC) ++ pages++; ++ if (unlikely(req->nr_segments == 0) || ++ unlikely(req->nr_segments ++ > USBIF_MAX_SEGMENTS_PER_REQUEST) || ++ (unlikely(pages != req->nr_segments) && !indirect)) { ++ debug_print(LOG_LVL_ERROR, ++ "Bad number of segments in request (%d : %d)\n", ++ req->nr_segments, pages); ++ goto fail_response; ++ } ++ ++ if ((err = map_request(pending_req, 0, usbif->domid, req->u.gref, ++ req->nr_segments, ++ !usbif_request_dir_in(req) || indirect, ++ 0))) { ++ debug_print(LOG_LVL_ERROR, ++ "map_request failed, err=%d\n",err); ++ goto fail_flush; ++ } ++ ++ if (indirect) { ++#ifdef INDIRECT_SEGMENTS ++ if ((err = setup_indirect(usbif, pending_req, pages, ++ !usbif_request_dir_in(req))) < 0) { ++ debug_print(LOG_LVL_ERROR, ++ "setup_indirect failed, err=%d\n",err); ++ goto fail_flush; ++ } ++#else ++ debug_print(LOG_LVL_ERROR, ++ "indirect specified but not compiled in\n"); ++ goto fail_flush; ++#endif ++ } ++ ++ ret = copy_out(pending_req); ++ if (unlikely(ret < 0)) { ++ debug_print(LOG_LVL_ERROR, ++ "copy iso failed urb %p, ret %d\n", urb, ret); ++ goto fail_flush; ++ } ++ } ++ ++ ret = vusb_setup_urb(&usbif->vusb, req, urb); ++ if (unlikely(ret < 0)) { ++ debug_print(LOG_LVL_ERROR, ++ "setup failed for urb %p, ret %d\n", urb, ret); ++ goto fail_flush; ++ } else if (unlikely(ret > 0)) { ++ debug_print(LOG_LVL_INFO, ++ "control success for urb %p\n", urb); ++ ret = 0; ++ goto early_success; ++ } ++ ++ usbif_get(usbif); ++ ++#ifdef USBBK_TIMEOUT ++ if (usbif_request_timeout(req)) { ++ debug_print(LOG_LVL_DEBUG, ++ "Timeout set for urb for %llu\n", req->id); ++ set_timeout(pending_req); ++ } ++#endif ++ ++ usb_anchor_urb(urb, &usbif->vusb.anchor); ++ ++ ret = usb_submit_urb(urb, GFP_KERNEL); ++ if (unlikely(ret < 0)) { ++ debug_print(LOG_LVL_ERROR, ++ "submit failed for urb %p, ret %d\n", urb, ret); ++ usb_unanchor_urb(urb); ++#ifdef USBBK_TIMEOUT ++ cancel_timeout(pending_req); ++#endif ++ usbif_put(usbif); ++ goto fail_flush; ++ } ++ ++ /* release our urb reference from the alloc, the core now owns it */ ++ usb_free_urb(urb); ++ ++ debug_print(LOG_LVL_INFO, "%s: Submitted urb for %llu\n", ++ __FUNCTION__, req->id); ++ ++ return; ++ ++ early_success: ++ fail_flush: ++ fast_flush_area(pending_req); ++ fail_response: ++ make_response(usbif, req->id, 0, 0, get_usb_status(ret), 0); ++ urb = pending_req->urb; ++ free_req(pending_req); ++ usb_free_urb(urb); ++} ++ ++ ++ ++/****************************************************************** ++ * MISCELLANEOUS SETUP / TEARDOWN / DEBUGGING ++ */ ++ ++ ++static void make_response(usbif_t *usbif, u64 id, int actual_length, ++ int data, int status, int error_count) ++{ ++ usbif_response_t resp; ++ unsigned long flags; ++ usbif_back_rings_t *usb_rings = &usbif->usb_rings; ++ int more_to_do = 0; ++ int notify; ++ ++ debug_print(LOG_LVL_INFO, ++ "%s: id %llu len %d data %d status %d\n", ++ __FUNCTION__, id, actual_length, data, status); ++ ++ if (status) ++ usbif->stats.st_error++; ++ ++ resp.id = id; ++ resp.actual_length = actual_length; ++ resp.data = data; ++ resp.status = status; ++ resp.error_count = error_count; /* used for ISOCH only */ ++ ++ spin_lock_irqsave(&usbif->usb_ring_lock, flags); ++ /* Place on the response ring for the relevant domain. */ ++ switch (usbif->usb_protocol) { ++ case USBIF_PROTOCOL_NATIVE: ++ memcpy(RING_GET_RESPONSE(&usb_rings->native, usb_rings->native.rsp_prod_pvt), ++ &resp, sizeof(resp)); ++ break; ++ case USBIF_PROTOCOL_X86_32: ++ memcpy(RING_GET_RESPONSE(&usb_rings->x86_32, usb_rings->x86_32.rsp_prod_pvt), ++ &resp, sizeof(resp)); ++ break; ++ case USBIF_PROTOCOL_X86_64: ++ memcpy(RING_GET_RESPONSE(&usb_rings->x86_64, usb_rings->x86_64.rsp_prod_pvt), ++ &resp, sizeof(resp)); ++ break; ++ default: ++ BUG(); ++ } ++ usb_rings->common.rsp_prod_pvt++; ++ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&usb_rings->common, notify); ++ if (usb_rings->common.rsp_prod_pvt == usb_rings->common.req_cons) { ++ /* ++ * Tail check for pending requests. Allows frontend to avoid ++ * notifications if requests are already in flight (lower ++ * overheads and promotes batching). ++ */ ++ RING_FINAL_CHECK_FOR_REQUESTS(&usb_rings->common, more_to_do); ++ ++ } else if (RING_HAS_UNCONSUMED_REQUESTS(&usb_rings->common)) { ++ more_to_do = 1; ++ } ++ ++ spin_unlock_irqrestore(&usbif->usb_ring_lock, flags); ++ ++ if (more_to_do) ++ usbif_notify_work(usbif); ++ ++ /* ++ * OXT-311 it is unlikely the Xen ring code is broken since it is ++ * the backbone of PV drivers. This needs investigation and fixing. ++ */ ++ /* always notify, there seems to be a bug in the Xen ring code */ ++ /*if (notify)*/ ++ notify_remote_via_irq(usbif->irq); ++} ++ ++static int __init usbif_init(void) ++{ ++ int i, mmap_pages; ++ ++ if (vusb_init()) ++ return -EINVAL; ++ ++ mmap_pages = usbif_reqs * USBIF_MAX_SEGMENTS_PER_REQUEST; ++ ++ pending_reqs = kzalloc(sizeof(pending_reqs[0]) * ++ usbif_reqs, GFP_KERNEL); ++ pending_pages = vzalloc(sizeof(pending_pages[0]) * mmap_pages); ++ ++ pending_segments = kzalloc(sizeof(pending_segments[0]) * ++ mmap_pages, GFP_KERNEL); ++ ++ if (!pending_reqs || !pending_pages || !pending_segments) ++ goto out_of_memory; ++ ++ if (gnttab_alloc_pages(mmap_pages, pending_pages)) ++ goto out_of_memory; ++ ++ INIT_LIST_HEAD(&pending_segments_free); ++ ++ for (i = 0; i < mmap_pages; i++) { ++ pending_segments[i].grant_handle = USBBACK_INVALID_HANDLE; ++ pending_segments[i].page = pending_pages[i]; ++ list_add_tail(&pending_segments[i].free_list, &pending_segments_free); ++ } ++ pending_segments_free_cnt = mmap_pages; ++ ++ usbif_interface_init(); ++ ++ INIT_LIST_HEAD(&pending_free); ++ ++ for (i = 0; i < usbif_reqs; i++) { ++ timer_setup(&pending_reqs[i].timer, NULL, 0); ++ list_add_tail(&pending_reqs[i].free_list, &pending_free); ++ } ++ ++ INIT_LIST_HEAD(&pending_to_free); ++ ++ if (usbif_xenbus_init()) { ++ pr_warning("Could not register xenbus backend for usbback.\n"); ++ BUG(); ++ } ++ ++ printk("USB backend driver intialized!\n"); ++ ++ return 0; ++ ++ out_of_memory: ++ kfree(pending_reqs); ++ kfree(pending_segments); ++ vfree(pending_pages); ++ printk("%s: out of memory\n", __FUNCTION__); ++ return -ENOMEM; ++} ++ ++module_init(usbif_init); ++ ++MODULE_LICENSE("Dual BSD/GPL"); +--- /dev/null ++++ b/drivers/usb/xen-usbback/vusb.c +@@ -0,0 +1,938 @@ ++/****************************************************************************** ++ * usbback/vusb.c ++ * ++ * Routines for managing virtual usb devices. ++ * ++ * Copyright (c) Citrix Systems Inc. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (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 "common.h" ++ ++struct vusb_map ++{ ++ int bus; ++ int device; ++ struct vusb *vusb; ++}; ++ ++#define VUSB_MAX_DEVICES 512 ++static struct vusb_map vusb_map[VUSB_MAX_DEVICES]; ++static spinlock_t vusb_map_lock; ++ ++ ++/* Add or update bus,dev to map to new vusb ++ There can be only one of each {bus,device} pair */ ++static int ++vusb_map_device(struct vusb *vusb, int bus, int device) ++{ ++ unsigned long flags; ++ int index; ++ int ret = -1; ++ ++ spin_lock_irqsave(&vusb_map_lock, flags); ++ for (index=0; indexvusb == NULL) || ((map->bus == bus) && (map->device == device)) ){ ++ if (map->vusb) ++ debug_print(LOG_LVL_ERROR, "%s: removing dup\n",__FUNCTION__); ++ map->vusb = vusb; ++ map->bus = bus; ++ map->device = device; ++ ret = 0; ++ break; ++ } ++ } ++ index++; ++ /* flush any remaining dulpicate pairs */ ++ while (indexbus == bus) && (map->device == device)) { ++ debug_print(LOG_LVL_ERROR, "%s: removing dup\n",__FUNCTION__); ++ map->vusb = NULL; ++ map->bus = 0; ++ map->device = 0; ++ } ++ index++; ++ } ++ ++ spin_unlock_irqrestore(&vusb_map_lock, flags); ++ ++ return ret; ++} ++ ++static int ++vusb_unmap_device(struct vusb *vusb) ++{ ++ unsigned long flags; ++ int index; ++ int ret = -1; ++ ++ spin_lock_irqsave(&vusb_map_lock, flags); ++ for (index=0; indexvusb == vusb) { ++ map->vusb = NULL; ++ map->bus = 0; ++ map->device = 0; ++ ret = 0; ++ break; ++ } ++ } ++ spin_unlock_irqrestore(&vusb_map_lock, flags); ++ ++ return ret; ++} ++ ++static struct vusb * ++vusb_find_device(int bus, int device) ++{ ++ unsigned long flags; ++ int index; ++ struct vusb *vusb = NULL; ++ ++ spin_lock_irqsave(&vusb_map_lock, flags); ++ for (index=0; indexvusb && (map->bus == bus) && (map->device == device)) { ++ vusb = map->vusb; ++ break; ++ } ++ } ++ spin_unlock_irqrestore(&vusb_map_lock, flags); ++ ++ return vusb; ++} ++ ++static void vusb_delete(struct kref *kref) ++{ ++ struct vusb *vusb = KREF_TO_VUSB(kref); ++ ++ debug_print(LOG_LVL_ERROR, "%s: vusb %p\n", __FUNCTION__, vusb); ++ vusb->active = 0; ++ ++ vusb_flush(vusb); ++} ++ ++static int vusb_probe(struct usb_interface *intf, ++ const struct usb_device_id *id) ++{ ++ struct usb_device *udev = interface_to_usbdev(intf); ++ int bus = udev->bus->busnum; ++ int port = udev->portnum; ++ int device = udev->devnum; ++ struct vusb *vusb = vusb_find_device(bus, device); ++ ++ debug_print(LOG_LVL_ERROR, "%s: intf %p vusb %p for %d:%d (port %d)\n", ++ __FUNCTION__, intf, vusb, bus, device, port); ++ ++ if (vusb) { ++ if (!vusb->active) { ++ /* ++ * The driver released all of its interfacesi, is now ++ * reprobing. reference counting needs to be restarted ++ * and the device marked active. ++ */ ++ kref_init(&vusb->kref); ++ vusb->active = 1; ++ } else { ++ kref_get(&vusb->kref); ++ } ++ usb_set_intfdata(intf, vusb); ++ return 0; ++ } ++ ++ return -ENODEV; ++} ++ ++static void vusb_disconnect(struct usb_interface *intf) ++{ ++ struct vusb *vusb = usb_get_intfdata(intf); ++ ++ debug_print(LOG_LVL_ERROR, "%s: intf %p vusb %p\n", ++ __FUNCTION__, intf, vusb); ++ ++ if (!vusb) ++ return; ++ ++ /* Mark the interface for later rebinding */ ++ intf->needs_binding = 1; ++ ++ usb_set_intfdata(intf, NULL); ++ kref_put(&vusb->kref, vusb_delete); ++} ++ ++static int vusb_suspend(struct usb_interface *intf, pm_message_t message) ++{ ++ struct vusb *vusb = usb_get_intfdata(intf); ++ ++ debug_print(LOG_LVL_ERROR, "%s: intf %p vusb %p\n", ++ __FUNCTION__, intf, vusb); ++ ++ if (!vusb || !vusb->initted) ++ return -1; ++ ++ usbback_suspend(usbif_from_vusb(vusb), 1); ++ vusb_flush(vusb); ++ return 0; ++} ++ ++static int vusb_resume(struct usb_interface *intf) ++{ ++ struct vusb *vusb = usb_get_intfdata(intf); ++ ++ debug_print(LOG_LVL_ERROR, "%s: intf %p vusb %p\n", ++ __FUNCTION__, intf, vusb); ++ ++ if (!vusb || !vusb->initted) ++ return -1; ++ ++ usbback_suspend(usbif_from_vusb(vusb), 0); ++ return 0; ++} ++ ++static int vusb_reset_resume(struct usb_interface *intf) ++{ ++ struct vusb *vusb = usb_get_intfdata(intf); ++ ++ debug_print(LOG_LVL_ERROR, "%s: intf %p vusb %p\n", ++ __FUNCTION__, intf, vusb); ++ ++ return vusb_resume(intf); ++} ++ ++static int vusb_pre_reset(struct usb_interface *intf) ++{ ++ struct vusb *vusb = usb_get_intfdata(intf); ++ ++ debug_print(LOG_LVL_ERROR, "%s: intf %p vusb %p\n", ++ __FUNCTION__, intf, vusb); ++ ++ if (!vusb) ++ return -ENODEV; ++ ++ vusb->canceling_requests = 1; ++ return 0; ++} ++ ++static int vusb_post_reset(struct usb_interface *intf) ++{ ++ struct vusb *vusb = usb_get_intfdata(intf); ++ ++ debug_print(LOG_LVL_ERROR, "%s: intf %p vusb %p\n", ++ __FUNCTION__, intf, vusb); ++ ++ if (!vusb) ++ return -ENODEV; ++ ++ vusb->canceling_requests = 0; ++ return 0; ++} ++ ++struct usb_driver vusb_driver = { ++ .name = "vusb", ++ .probe = vusb_probe, ++ .disconnect = vusb_disconnect, ++ .suspend = vusb_suspend, ++ .resume = vusb_resume, ++ .reset_resume = vusb_reset_resume, ++ .pre_reset = vusb_pre_reset, ++ .post_reset = vusb_post_reset, ++ .supports_autosuspend = 1, ++ .soft_unbind = 0, ++}; ++ ++static int ++vusb_claim_interface(struct vusb *vusb, struct usb_interface *intf) ++{ ++ struct device *dev = &intf->dev; ++ int ret; ++ ++ debug_print(LOG_LVL_DEBUG, ++ "%s: claim interface if %p, vusb %p\n", __FUNCTION__, intf, vusb); ++ ++ if (dev->driver) { ++ struct usb_driver *driver = to_usb_driver(dev->driver); ++ ++ /* Even if this driver already owns it, its probably with ++ * the wrong vusb, so we still need to release it, and ++ * claim it properly ++ */ ++ ++ if (driver == &vusb_driver) { ++ struct vusb *old_vusb = usb_get_intfdata(intf); ++ debug_print(LOG_LVL_ERROR, ++ "%s: release ourselves with vusb %p " ++ "from interface if %p\n", __FUNCTION__, ++ old_vusb,intf); ++ } else { ++ debug_print(LOG_LVL_ERROR, ++ "%s: release old driver from interface if %p\n", ++ __FUNCTION__, intf); ++ } ++ usb_driver_release_interface(driver, intf); ++ } ++ ++ ret = usb_driver_claim_interface(&vusb_driver, intf, vusb); ++ if (ret) ++ debug_print(LOG_LVL_ERROR, ++ "%s: claim_interface failed for if %p ret %d\n", ++ __FUNCTION__, intf, ret); ++ else ++ usb_set_intfdata(intf, vusb); ++ ++ return (ret); ++} ++ ++static void ++vusb_claim_config(struct vusb *vusb, struct usb_host_config *config) ++{ ++ unsigned int ifs = config->desc.bNumInterfaces; ++ unsigned int ifnum; ++ ++ for (ifnum = 0; ifnum < ifs; ifnum++) { ++ struct usb_interface *intf = config->interface[ifnum]; ++ ++ /* ++ * If there is an interface and we end up with ownership, ++ * count it. ++ */ ++ if (intf && (vusb_claim_interface(vusb, intf) == 0)) ++ kref_get(&vusb->kref); ++ } ++} ++ ++/* precondition: usb_lock_device should be called */ ++ ++static void ++vusb_claim_dev(struct vusb *vusb, struct usb_device *udev) ++{ ++ unsigned int confs = udev->descriptor.bNumConfigurations; ++ unsigned int confnum; ++ ++ debug_print(LOG_LVL_ERROR, ++ "%s: claim device %p (%d.%d (port %d)), vusb %p\n", __FUNCTION__, ++ udev, udev->bus->busnum, udev->devnum, udev->portnum, vusb); ++ ++ for (confnum = 0; confnum < confs; confnum++) { ++ struct usb_host_config *config = &udev->config[confnum]; ++ ++ if (config) ++ vusb_claim_config(vusb, config); ++ } ++ return; ++} ++ ++static void ++vusb_release_config(struct vusb *vusb, struct usb_host_config *config) ++{ ++ unsigned int ifnum; ++ ++ debug_print(LOG_LVL_DEBUG, "%s[%d]: vusb %p config %p\n", ++ __FUNCTION__, __LINE__, vusb, config); ++ ++ for (ifnum = 0; ifnum < config->desc.bNumInterfaces; ifnum++) { ++ struct usb_interface *intf = config->interface[ifnum]; ++ struct device *dev = &intf->dev; ++ struct usb_driver *driver = to_usb_driver(dev->driver); ++ ++ /* ++ * Only release the interface if we own it. Releasing it will ++ * result in our disconnect handler being called. ++ */ ++ if (driver == &vusb_driver) { ++ struct vusb *old_vusb = usb_get_intfdata(intf); ++ if (old_vusb == vusb) { ++ debug_print(LOG_LVL_ERROR, "%s[%d]: vusb %p intf %p\n", ++ __FUNCTION__, __LINE__, vusb, intf); ++ usb_driver_release_interface(&vusb_driver, intf); ++ } else { ++ debug_print(LOG_LVL_ERROR, "%s[%d]: not releasing vusb %p config %p\n", ++ __FUNCTION__, __LINE__, old_vusb, config); ++ } ++ } ++ } ++} ++ ++static void vusb_release_dev(struct vusb *vusb, struct usb_device *udev) ++{ ++ debug_print(LOG_LVL_DEBUG, "%s[%d]: vusb %p dev %p (%d.%d (port %d))\n", ++ __FUNCTION__, __LINE__, vusb, udev, ++ udev->bus->busnum, udev->devnum, udev->portnum); ++ ++ if (udev->actconfig) ++ vusb_release_config(vusb, udev->actconfig); ++ ++ return; ++} ++ ++int vusb_init(void) ++{ ++ spin_lock_init(&vusb_map_lock); ++ ++ return usb_register(&vusb_driver); ++} ++ ++void vusb_cleanup(void) ++{ ++ usb_deregister(&vusb_driver); ++} ++ ++int vusb_create(usbif_t *usbif, usbif_vdev_t handle, unsigned bus, ++ unsigned device) ++{ ++ struct vusb *vusb; ++ struct usb_device *usbdev; ++ ++ vusb = &usbif->vusb; ++ vusb->handle = handle; ++ vusb->bus = bus; ++ vusb->device = device; ++ vusb->active = 1; ++ ++ kref_init(&vusb->kref); ++ ++ init_usb_anchor(&vusb->anchor); ++ ++ usbdev = dusb_open(bus, device); ++ if (NULL == usbdev) { ++ printk("VUSB: failed to open %d.%d\n", bus, device); ++ return -1; ++ } ++ ++ usb_lock_device(usbdev); ++ vusb_map_device(vusb, bus, device); ++ ++ /* validate */ ++ if ((device != usbdev->devnum) || (bus != usbdev->bus->busnum)) ++ debug_print(LOG_LVL_ERROR, "Device mismatch %d.%d vs %d.%d\n", ++ bus, device, usbdev->devnum, usbdev->bus->busnum); ++ ++ vusb_claim_dev(vusb, usbdev); ++ vusb->usbdev = usbdev; ++ vusb->max_sgs = usbdev->bus->sg_tablesize; ++ vusb->hcd_speed = dusb_dev_controller_speed(usbdev); ++ /* EHCI fails unaligned transfers with BABBLE (EOVERFLOW) */ ++ vusb->copy_unaligned = (vusb->hcd_speed != USB_SPEED_SUPER); ++ ++ /* don't allow the device to suspend until the frontend says so */ ++ usb_disable_autosuspend(usbdev); ++ ++ vusb->initted = 1; ++ ++ usb_unlock_device(usbdev); ++ kref_put(&vusb->kref, vusb_delete); ++ ++ debug_print(LOG_LVL_ERROR, ++ "Created vusb %p (%d) device %d.%d (dom=%u) max sgs %u\n", ++ vusb, vusb->kref.refcount.refs.counter, bus, device, usbif->domid, ++ vusb->max_sgs); ++ debug_print(LOG_LVL_ERROR, ++ "VUSB: device %s - %s - %s speed %s on %s\n", ++ usbdev->product, usbdev->manufacturer, usbdev->serial, ++ (usbdev->speed == USB_SPEED_SUPER) ? "super" : ++ (usbdev->speed == USB_SPEED_HIGH) ? "high" : "low", ++ (vusb->hcd_speed == USB_SPEED_SUPER) ? "super" : ++ (vusb->hcd_speed == USB_SPEED_HIGH) ? "high" : "low"); ++ return 0; ++} ++ ++void vusb_free(struct vusb *vusb) ++{ ++ struct usb_device *usbdev = vusb->usbdev; ++ ++ if (usbdev) { ++ usb_lock_device(usbdev); ++ ++ debug_print(LOG_LVL_ERROR, "VUSB: close device %s %s %s\n", ++ usbdev->product, usbdev->manufacturer, usbdev->serial); ++ ++ vusb->usbdev = NULL; ++ vusb_unmap_device(vusb); ++ ++ /* flush any remaining requests */ ++ vusb_flush(vusb); ++ ++ /* ++ * If we haven't received cleanup callbacks from the USB side ++ * yet, do the USB cleanup. ++ */ ++ if (vusb->active) ++ vusb_release_dev(vusb, usbdev); ++ ++ usb_unlock_device(usbdev); ++ dusb_close(usbdev); ++ } ++} ++ ++static char * setup_type(int type) ++{ ++ switch((type & USB_TYPE_MASK)) { ++ case USB_TYPE_STANDARD: ++ return "standard"; ++ case USB_TYPE_CLASS: ++ return "class"; ++ case USB_TYPE_VENDOR: ++ return "reserved"; ++ case USB_TYPE_RESERVED: ++ default: ++ return "reserved"; ++ } ++} ++ ++static char * setup_recip(int type) ++{ ++ switch((type & USB_RECIP_MASK)) { ++ case USB_RECIP_DEVICE: ++ return "device"; ++ case USB_RECIP_INTERFACE: ++ return "interface"; ++ case USB_RECIP_ENDPOINT: ++ return "endpoint"; ++ case USB_RECIP_OTHER: ++ return "other"; ++ case USB_RECIP_PORT: ++ return "port"; ++ case USB_RECIP_RPIPE: ++ return "rpipe"; ++ default: ++ return "recip unknown"; ++ } ++} ++ ++static int maybe_set_configuration(struct usb_device *dev, int configuration) ++{ ++ struct usb_host_config *cp = NULL; ++ int i; ++ ++ for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { ++ if (dev->config[i].desc.bConfigurationValue == ++ configuration) { ++ cp = &dev->config[i]; ++ break; ++ } ++ } ++ if (cp && cp == dev->actconfig) ++ return 0; ++ return dusb_set_configuration(dev, configuration); ++} ++ ++static int setup_control_urb(struct vusb *vusb, usbif_request_t *req, ++ struct urb *urb) ++{ ++ struct usb_device *usbdev = vusb->usbdev; ++ usbif_stats_t *stats = &(usbif_from_vusb(vusb)->stats); ++ struct usb_ctrlrequest *setup = ++ (struct usb_ctrlrequest *)urb->setup_packet; ++ int value, index, length; ++ int ret = 0; ++ ++ memcpy(urb->setup_packet, &req->setup, sizeof(struct usb_ctrlrequest)); ++ ++ value = __le16_to_cpup(&setup->wValue); ++ index = __le16_to_cpup(&setup->wIndex); ++ length = __le16_to_cpup(&setup->wLength); ++ ++ debug_print(LOG_LVL_DEBUG, ++ "%s: setup: %s %s %s req %x val %x idx %x len %x\n", ++ __FUNCTION__, ++ (setup->bRequestType & USB_DIR_IN) ? "IN" : "OUT", ++ setup_type(setup->bRequestType), ++ setup_recip(setup->bRequestType), ++ (int)setup->bRequest, ++ value, index, length); ++ ++ switch (setup->bRequestType & USB_RECIP_MASK) { ++ case USB_RECIP_DEVICE: ++ if (setup->bRequest == USB_REQ_CLEAR_FEATURE) { ++ debug_print(LOG_LVL_DEBUG, "clear feature\n"); ++ } else if (setup->bRequest == USB_REQ_SET_CONFIGURATION) { ++ int confnum = value; ++ ++ debug_print(LOG_LVL_DEBUG, "set config %d\n", confnum); ++ ++ usb_lock_device(usbdev); ++ ret = maybe_set_configuration(usbdev, confnum); ++ usb_unlock_device(usbdev); ++ if (ret == 0) ++ return (1); ++ } else if (setup->bRequest == USB_REQ_GET_DESCRIPTOR) { ++ int type = value >> 8; ++ int id = value & 0xff; ++ ++ if ((type == USB_DT_STRING) && (id > 0)) { ++ debug_print(LOG_LVL_DEBUG, ++ "get string descriptor index %d language %x\n", ++ id, index); ++ } else { ++ debug_print(LOG_LVL_DEBUG, ++ "get descriptor type %d index %d\n", ++ type, id); ++ } ++ } ++ break; ++ ++ case USB_RECIP_INTERFACE: ++ if (setup->bRequest == USB_REQ_CLEAR_FEATURE) { ++ debug_print(LOG_LVL_DEBUG, "clear feature\n"); ++ } else if (setup->bRequest == USB_REQ_SET_INTERFACE) { ++ int ifnum = index; ++ int alt = value; ++ ++ debug_print(LOG_LVL_DEBUG, "set interface %d\n", ifnum); ++ ++ ret = usb_set_interface(usbdev, ifnum, alt); ++ if (ret == 0) ++ return (1); ++ } ++ break; ++ ++ case USB_RECIP_ENDPOINT: ++ if (setup->bRequest == USB_REQ_GET_STATUS) { ++ debug_print(LOG_LVL_DEBUG, "get status %d\n", index); ++ } else if ((setup->bRequest == USB_REQ_CLEAR_FEATURE) && ++ (value == USB_ENDPOINT_HALT)) { ++ int ep = index; ++ int epnum = ep & 0x7f; ++ int pipe; ++ ++ debug_print(LOG_LVL_DEBUG, "clear halt %d\n", epnum); ++ if (ep & USB_DIR_IN) ++ pipe = usb_rcvbulkpipe(usbdev, epnum); ++ else ++ pipe = usb_sndbulkpipe(usbdev, epnum); ++ ret = usb_clear_halt(usbdev, pipe); ++ if ((ret == 0) || (ret == -EPIPE)) ++ return (1); ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ urb->interval = 1; ++ ++ if (usbif_request_dir_in(req)) { ++ urb->pipe = usb_rcvctrlpipe(usbdev, ++ usbif_request_endpoint_num(req)); ++ stats->st_in_req++; ++ } else { ++ urb->pipe = usb_sndctrlpipe(usbdev, ++ usbif_request_endpoint_num(req)); ++ stats->st_out_req++; ++ } ++ stats->st_cntrl_req++; ++ ++ return (ret); ++} ++ ++static void setup_isoc_urb(struct vusb *vusb, usbif_request_t *req, ++ struct urb *urb, struct usb_host_endpoint *ep) ++{ ++ struct usb_device *usbdev = vusb->usbdev; ++ usbif_stats_t *stats = &(usbif_from_vusb(vusb)->stats); ++ ++ urb->interval = 1 << min(15, ep->desc.bInterval - 1); ++ urb->start_frame = req->startframe; ++ ++ if (usbif_request_asap(req)) ++ urb->transfer_flags |= URB_ISO_ASAP; ++ ++ debug_print(LOG_LVL_DEBUG, "%s: interval %x sf %d packets %d\n", ++ __FUNCTION__, urb->interval, urb->start_frame, ++ urb->number_of_packets); ++ ++ if (usbif_request_dir_in(req)) { ++ urb->pipe = usb_rcvisocpipe(usbdev, ++ usbif_request_endpoint_num(req)); ++ stats->st_in_req++; ++ } else { ++ urb->pipe = usb_sndisocpipe(usbdev, ++ usbif_request_endpoint_num(req)); ++ stats->st_out_req++; ++ } ++ stats->st_isoc_req++; ++} ++ ++static void setup_bulk_urb(struct vusb *vusb, usbif_request_t *req, ++ struct urb *urb) ++{ ++ struct usb_device *usbdev = vusb->usbdev; ++ usbif_stats_t *stats = &(usbif_from_vusb(vusb)->stats); ++ ++ debug_print(LOG_LVL_DEBUG, "%s\n", __FUNCTION__); ++ ++ urb->interval = 1; ++ ++ if (usbif_request_dir_in(req)) { ++ urb->pipe = usb_rcvbulkpipe(usbdev, ++ usbif_request_endpoint_num(req)); ++ stats->st_in_req++; ++ } else { ++ urb->pipe = usb_sndbulkpipe(usbdev, ++ usbif_request_endpoint_num(req)); ++ stats->st_out_req++; ++ } ++ stats->st_bulk_req++; ++} ++ ++static void setup_int_urb(struct vusb *vusb, usbif_request_t *req, ++ struct urb *urb, struct usb_host_endpoint *ep) ++{ ++ struct usb_device *usbdev = vusb->usbdev; ++ usbif_stats_t *stats = &(usbif_from_vusb(vusb)->stats); ++ ++ switch (usbdev->speed) { ++ case USB_SPEED_HIGH: ++ case USB_SPEED_SUPER: ++ urb->interval = 1 << min(15, ep->desc.bInterval - 1); ++ break; ++ case USB_SPEED_FULL: ++ case USB_SPEED_LOW: ++ urb->interval = ep->desc.bInterval; ++ break; ++ default: ++ debug_print(LOG_LVL_ERROR, "%s: bad speed %x\n", ++ __FUNCTION__, usbdev->speed); ++ break; ++ } ++ ++ debug_print(LOG_LVL_DEBUG, "%s: interval %x\n", __FUNCTION__, ++ urb->interval); ++ ++ if (usbif_request_dir_in(req)) { ++ urb->pipe = usb_rcvintpipe(usbdev, ++ usbif_request_endpoint_num(req)); ++ stats->st_in_req++; ++ } else { ++ urb->pipe = usb_sndintpipe(usbdev, ++ usbif_request_endpoint_num(req)); ++ stats->st_out_req++; ++ } ++ stats->st_int_req++; ++} ++ ++static struct usb_device *vusb_device(struct vusb *vusb) ++{ ++ return ((vusb->active && vusb->usbdev && ++ dusb_dev_running(vusb->usbdev)) ? vusb->usbdev : NULL); ++} ++ ++int vusb_setup_urb(struct vusb *vusb, usbif_request_t *req, struct urb *urb) ++{ ++ struct usb_device *usbdev = vusb_device(vusb); ++ struct usb_host_endpoint *ep; ++ int endpointnum = usbif_request_endpoint_num(req); ++ int ret = 0; ++ ++ if ((usbdev == NULL) || ((usbdev->state != USB_STATE_ADDRESS) && ++ (usbdev->state != USB_STATE_CONFIGURED))) { ++ return -ENODEV; ++ } ++ ++ if (usbif_request_dir_in(req)) ++ ep = usbdev->ep_in[endpointnum]; ++ else ++ ep = usbdev->ep_out[endpointnum]; ++ if (!ep) { ++ debug_print(LOG_LVL_ERROR, "endpoint not found (%d)\n", endpointnum); ++ return -ENOENT; ++ } ++ ++ urb->dev = usbdev; ++ if (!usbif_request_shortok(req) && usbif_request_dir_in(req)) ++ urb->transfer_flags |= URB_SHORT_NOT_OK; ++ ++ switch((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)) { ++ case USB_ENDPOINT_XFER_CONTROL: ++ ret = setup_control_urb(vusb, req, urb); ++ break; ++ ++ case USB_ENDPOINT_XFER_ISOC: ++ setup_isoc_urb(vusb, req, urb, ep); ++ break; ++ ++ case USB_ENDPOINT_XFER_BULK: ++ setup_bulk_urb(vusb, req, urb); ++ break; ++ ++ default: ++ case USB_ENDPOINT_XFER_INT: ++ setup_int_urb(vusb, req, urb, ep); ++ break; ++ } ++ ++ return (ret); ++} ++ ++int vusb_reset_device(struct vusb *vusb) ++{ ++ struct usb_device *usbdev = vusb_device(vusb); ++ usbif_stats_t *stats = &(usbif_from_vusb(vusb)->stats); ++ int ret; ++ ++ if (!usbdev) ++ return (-1); ++ ++ debug_print(LOG_LVL_ERROR, "%s vusb %p, usbdev %p (%d.%d (port %d)) Start\n", ++ __FUNCTION__, vusb, usbdev, ++ usbdev->bus->busnum, usbdev->devnum, usbdev->portnum); ++ ++ /* pre and post reset handlers set and clear canceling_requests */ ++ usb_lock_device(usbdev); ++ ret = usb_reset_device(usbdev); ++ usb_unlock_device(usbdev); ++ ++ stats->st_reset++; ++ ++ debug_print(LOG_LVL_ERROR, "%s vusb %p, usbdev %p (%d.%d (port %d)) Done\n", ++ __FUNCTION__, vusb, usbdev, ++ usbdev->bus->busnum, usbdev->devnum, usbdev->portnum); ++ ++ return ret; ++} ++ ++void vusb_flush(struct vusb *vusb) ++{ ++ debug_print(LOG_LVL_INFO, "%s\n", __FUNCTION__); ++ ++ vusb->canceling_requests = 1; ++ ++ usb_kill_anchored_urbs(&vusb->anchor); ++ ++ vusb->canceling_requests = 0; ++} ++ ++int vusb_flush_endpoint(struct vusb *vusb, usbif_request_t *req) ++{ ++ int endpointnum = usbif_request_endpoint_num(req); ++ struct usb_device *usbdev = vusb_device(vusb); ++ struct usb_host_endpoint *ep; ++ ++ debug_print(LOG_LVL_DEBUG, "%s udev %p\n", __FUNCTION__, usbdev); ++ ++ if (usbdev) { ++ if (usbif_request_dir_in(req)) ++ ep = usbdev->ep_in[endpointnum]; ++ else ++ ep = usbdev->ep_out[endpointnum]; ++ if (!ep) { ++ debug_print(LOG_LVL_ERROR, "endpoint not found (%d)\n", endpointnum); ++ return -ENOENT; ++ } ++ ++ vusb->canceling_requests = 1; ++ ++ dusb_flush_endpoint(usbdev, ep); ++ ++ vusb->canceling_requests = 0; ++ } else { ++ vusb_flush(vusb); ++ } ++ ++ debug_print(LOG_LVL_DEBUG, "%s - udev %p end\n", __FUNCTION__, usbdev); ++ ++ return (0); ++} ++ ++int vusb_get_speed(struct vusb *vusb) ++{ ++ struct usb_device *usbdev = vusb_device(vusb); ++ ++ return (usbdev ? usbdev->speed : -1); ++} ++ ++void vusb_free_coherent(struct vusb *vusb, struct urb *urb) ++{ ++ struct usb_device *usbdev = urb->dev ? urb->dev : vusb->usbdev; ++ ++ if (usbdev) ++ usb_free_coherent(usbdev, urb->transfer_buffer_length, ++ urb->transfer_buffer, urb->transfer_dma); ++ else ++ debug_print(LOG_LVL_ERROR, "%s: leaking buffer! no dev!", ++ __FUNCTION__); ++ urb->transfer_buffer = NULL; ++} ++ ++void *vusb_alloc_coherent(struct vusb *vusb, size_t size, dma_addr_t *dma) ++{ ++ struct usb_device *usbdev = vusb_device(vusb); ++ ++ void *ret = (usbdev ? usb_alloc_coherent(usbdev, size, GFP_KERNEL, dma) : NULL); ++ ++ if (!ret) { ++ debug_print((usbdev != NULL) ? LOG_LVL_DEBUG : LOG_LVL_ERROR, ++ "%s: Failed: vusb:%p, udbdev:%p, " ++ "active:%d, running:%s\n", ++ __FUNCTION__, ++ vusb, vusb->usbdev, vusb->active, ++ usbdev && dusb_dev_running(usbdev) ? "yes" : "no"); ++ } ++ ++ return (ret); ++} ++ ++void vusb_cycle_port(struct vusb *vusb) ++{ ++ struct usb_device *usbdev = vusb_device(vusb); ++ ++ if (usbdev) { ++ debug_print(LOG_LVL_ERROR, "%s vusb %p, usbdev %p (%d.%d (port %d)) Start\n", ++ __FUNCTION__, vusb, usbdev, ++ usbdev->bus->busnum, usbdev->devnum, usbdev->portnum); ++ usb_device_reenumerate(usbdev); ++ debug_print(LOG_LVL_ERROR, "%s vusb %p, usbdev %p (%d.%d (port %d)) Done\n", ++ __FUNCTION__, vusb, usbdev, ++ usbdev->bus->busnum, usbdev->devnum, usbdev->portnum); ++ } ++} ++ ++ ++/* power management methods */ ++void vusb_pm_autosuspend_control(struct vusb *vusb, int enable) ++{ ++ struct usb_device *usbdev = vusb_device(vusb); ++ ++ if (usbdev && (vusb->autosuspend != enable)) { ++ debug_print(LOG_LVL_INFO, "%s vusb %p, udev %p enable %d\n", ++ __FUNCTION__, vusb, usbdev, enable); ++ ++ vusb->autosuspend = enable; ++ if (enable) ++ usb_enable_autosuspend(usbdev); ++ else ++ usb_disable_autosuspend(usbdev); ++ } ++} ++ +--- /dev/null ++++ b/drivers/usb/xen-usbback/xenbus.c +@@ -0,0 +1,583 @@ ++/* Xenbus code for usbif backend ++ Copyright (C) 2005 Rusty Russell ++ Copyright (C) 2005 XenSource Ltd ++ Copyright (C) 2008-2012 Virtual Computer Inc. ++ ++ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++*/ ++ ++#include ++#include ++#include ++#include "common.h" ++ ++#undef DPRINTK ++#define DPRINTK(fmt, args...) \ ++ pr_debug("usbback/xenbus (%s:%d) " fmt ".\n", \ ++ __FUNCTION__, __LINE__, ##args) ++ ++static void connect(struct backend_info *); ++static int connect_ring(struct backend_info *); ++ ++static void update_usbif_status(usbif_t *usbif) ++{ ++ int err; ++ char name[TASK_COMM_LEN]; ++ ++ /* Not ready to connect? */ ++ if (!usbif->irq) ++ return; ++ ++ /* Already connected? */ ++ if (usbif->be->dev->state == XenbusStateConnected) ++ return; ++ ++ /* Attempt to connect: exit if we fail to. */ ++ connect(usbif->be); ++ if (usbif->be->dev->state != XenbusStateConnected) ++ return; ++ ++ snprintf(name, TASK_COMM_LEN, "usbback.%d.%d.%d", ++ usbif->domid, usbif->be->bus, usbif->be->device); ++ ++ usbif->xenusbd = kthread_run(usbif_schedule, usbif, name); ++ if (IS_ERR(usbif->xenusbd)) { ++ err = PTR_ERR(usbif->xenusbd); ++ usbif->xenusbd = NULL; ++ xenbus_dev_error(usbif->be->dev, err, "start xenusbd"); ++ } ++ else ++ debug_print(LOG_LVL_DEBUG, "Started xenusbd\n"); ++} ++ ++/**************************************************************** ++ * sysfs interface for VUSB I/O requests ++ */ ++#define USB_SHOW(name, format, args...) \ ++ static ssize_t show_##name(struct device *_dev, \ ++ struct device_attribute *attr, \ ++ char *buf) \ ++ { \ ++ ssize_t ret = -ENODEV; \ ++ struct xenbus_device *dev; \ ++ struct backend_info *be; \ ++ \ ++ if (!get_device(_dev)) \ ++ return ret; \ ++ dev = to_xenbus_device(_dev); \ ++ if ((be = dev_get_drvdata(&dev->dev)) != NULL) \ ++ ret = sprintf(buf, format, ##args); \ ++ put_device(_dev); \ ++ return ret; \ ++ } \ ++ static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) ++ ++ ++USB_SHOW(oo_req, "%d\n", be->usbif->stats.st_oo_req); ++USB_SHOW(in_req, "%d\n", be->usbif->stats.st_in_req); ++USB_SHOW(out_req, "%d\n", be->usbif->stats.st_out_req); ++ ++USB_SHOW(error, "%d\n", be->usbif->stats.st_error); ++USB_SHOW(reset, "%d\n", be->usbif->stats.st_reset); ++ ++USB_SHOW(in_bandwidth, "%d\n", be->usbif->stats.st_in_bandwidth); ++USB_SHOW(out_bandwidth, "%d\n", be->usbif->stats.st_out_bandwidth); ++ ++USB_SHOW(cntrl_req, "%d\n", be->usbif->stats.st_cntrl_req); ++USB_SHOW(isoc_req, "%d\n", be->usbif->stats.st_isoc_req); ++USB_SHOW(bulk_req, "%d\n", be->usbif->stats.st_bulk_req); ++USB_SHOW(int_req, "%d\n", be->usbif->stats.st_int_req); ++ ++static struct attribute *usbstat_attrs[] = { ++ &dev_attr_oo_req.attr, ++ &dev_attr_in_req.attr, ++ &dev_attr_out_req.attr, ++ &dev_attr_error.attr, ++ &dev_attr_reset.attr, ++ &dev_attr_in_bandwidth.attr, ++ &dev_attr_out_bandwidth.attr, ++ &dev_attr_cntrl_req.attr, ++ &dev_attr_isoc_req.attr, ++ &dev_attr_bulk_req.attr, ++ &dev_attr_int_req.attr, ++ NULL ++}; ++ ++static struct attribute_group usbstat_group = { ++ .name = "statistics", ++ .attrs = usbstat_attrs, ++}; ++ ++USB_SHOW(physical_device, "%x.%x\n", be->bus, be->device); ++ ++int xenusb_sysfs_addif(struct xenbus_device *dev) ++{ ++ int error; ++ ++ error = device_create_file(&dev->dev, &dev_attr_physical_device); ++ if (error) ++ goto fail1; ++ ++ error = sysfs_create_group(&dev->dev.kobj, &usbstat_group); ++ if (error) ++ goto fail2; ++ ++ return 0; ++ ++fail2: sysfs_remove_group(&dev->dev.kobj, &usbstat_group); ++fail1: device_remove_file(&dev->dev, &dev_attr_physical_device); ++ return error; ++} ++ ++void xenusb_sysfs_delif(struct xenbus_device *dev) ++{ ++ sysfs_remove_group(&dev->dev.kobj, &usbstat_group); ++ device_remove_file(&dev->dev, &dev_attr_physical_device); ++} ++ ++static int usbback_remove(struct xenbus_device *dev) ++{ ++ struct backend_info *be = dev_get_drvdata(&dev->dev); ++ ++ debug_print(LOG_LVL_ERROR, "usbback_remove\n"); ++ ++ if (be->bus || be->device) ++ xenusb_sysfs_delif(dev); ++ ++ if (be->backend_watch.node) { ++ unregister_xenbus_watch(&be->backend_watch); ++ kfree(be->backend_watch.node); ++ be->backend_watch.node = NULL; ++ } ++ ++ if (be->autosuspend_watch.node) { ++ unregister_xenbus_watch(&be->autosuspend_watch); ++ kfree(be->autosuspend_watch.node); ++ be->autosuspend_watch.node = NULL; ++ } ++ ++ if (be->usbif) { ++ usbif_t *usbif = be->usbif; ++ ++ /* ++ * Disconnect the be and usbif since the call to vusb_free can ++ * cause callbacks like usbback_suspend which dereference ++ * usbif to be and make calls on the be. ++ */ ++ be->usbif = NULL; ++ usbif->be = NULL; ++ /* ++ * Kill the per device kthread so we don't process any more ++ * frontend requests. ++ */ ++ debug_print(LOG_LVL_ERROR, "Disconnecting vusb %p\n", &usbif->vusb); ++ usbif_disconnect(usbif, be->dev); ++ /* Shutdown the Linux USB class driver */ ++ debug_print(LOG_LVL_ERROR, "Freeing vusb %p\n", &usbif->vusb); ++ vusb_free(&usbif->vusb); ++ usbif_free(usbif); ++ } ++ ++ kfree(be); ++ dev_set_drvdata(&dev->dev, NULL); ++ return 0; ++} ++ ++int usbback_barrier(struct xenbus_transaction xbt, ++ struct backend_info *be, int state) ++{ ++ struct xenbus_device *dev = be->dev; ++ int err; ++ ++ err = xenbus_printf(xbt, dev->nodename, "feature-barrier", ++ "%d", state); ++ if (err) ++ xenbus_dev_fatal(dev, err, "writing feature-barrier"); ++ ++ return err; ++} ++ ++/* tell the frontend that the device's suspend state has changed */ ++int usbback_suspend(usbif_t *usbif, int suspended) ++{ ++ struct xenbus_device *dev = usbif->be ? usbif->be->dev : NULL; ++ int err; ++ ++ debug_print(LOG_LVL_ERROR, "%s: usbif %p dev %p node %s\n", ++ __FUNCTION__, usbif, dev, dev ? dev->nodename : ""); ++ ++ if (dev) ++ err = 0; ++ else ++ err = -ENODEV; ++ ++ return err; ++} ++ ++/** ++ * Callback received when the hotplug scripts have placed the physical-device ++ * node. Read it and create a vusb. If the frontend is ready, connect. ++ */ ++static void backend_changed(struct xenbus_watch *watch, ++ const char *path, const char *token) ++{ ++ int err; ++ unsigned bus; ++ unsigned device; ++ struct backend_info *be ++ = container_of(watch, struct backend_info, backend_watch); ++ struct xenbus_device *dev = be->dev; ++ ++ err = xenbus_scanf(XBT_NIL, dev->nodename, "physical-device", "%d.%d", ++ &bus, &device); ++ if (XENBUS_EXIST_ERR(err)) { ++ /* Since this watch will fire once immediately after it is ++ registered, we expect this. Ignore it, and wait for the ++ hotplug scripts. */ ++ return; ++ } ++ if (err != 2) { ++ xenbus_dev_fatal(dev, err, "reading physical-device"); ++ return; ++ } ++ ++ if ((be->bus || be->device) && (bus || device) && ++ ((be->bus != bus) || (be->device != device))) { ++ debug_print(LOG_LVL_ERROR, ++ "usbback: changing physical device (from %x.%x to " ++ "%x.%x) not supported.\n", be->bus, be->device, ++ bus, device); ++ return; ++ } ++ ++ if (be->bus == 0 && be->device == 0) { ++ /* Front end dir is a number, which is used as the handle. */ ++ ++ char *p = strrchr(dev->otherend, '/') + 1; ++ long handle = simple_strtoul(p, NULL, 0); ++ ++ be->bus = bus; ++ be->device = device; ++ ++ err = vusb_create(be->usbif, handle, bus, device); ++ if (err) { ++ be->bus = be->device = 0; ++ xenbus_dev_fatal(dev, err, "creating vusb structure"); ++ return; ++ } ++ ++ err = xenusb_sysfs_addif(dev); ++ if (err) { ++ vusb_free(&be->usbif->vusb); ++ be->bus = be->device = 0; ++ xenbus_dev_fatal(dev, err, "creating sysfs entries"); ++ return; ++ } ++ ++ /* We're potentially connected now */ ++ update_usbif_status(be->usbif); ++ } else if (bus == 0 && device == 0) { ++ /* Device is being unassigned -- simulate hot unplug */ ++ vusb_cycle_port(&be->usbif->vusb); ++ } ++} ++ ++/** ++ * Callback received when the frontend changes the atosuspend element. ++ */ ++static void autosuspend_changed(struct xenbus_watch *watch, ++ const char *path, const char* token) ++{ ++ struct backend_info *be ++ = container_of(watch, struct backend_info, autosuspend_watch); ++ struct xenbus_device *dev = be->dev; ++ unsigned autosuspend; ++ int err; ++ ++ err = xenbus_scanf(XBT_NIL, dev->otherend, "autosuspend", "%d", ++ &autosuspend); ++ if (XENBUS_EXIST_ERR(err)) { ++ /* Since this watch will fire once immediately after it is ++ registered, we expect this. Ignore it, and wait for the ++ hotplug scripts. */ ++ return; ++ } ++ if (err != 1) { ++ xenbus_dev_error(dev, err, "reading autosuspend"); ++ return; ++ } ++ ++ err = xenbus_scanf(XBT_NIL, dev->otherend, "autosuspend", "%d", ++ &autosuspend); ++ vusb_pm_autosuspend_control(&be->usbif->vusb, autosuspend); ++ ++ debug_print(LOG_LVL_INFO, "Autosuspend changed %d\n", autosuspend); ++} ++ ++ ++/** ++ * Entry point to this code when a new device is created. Allocate the basic ++ * structures, and watch the store waiting for the hotplug scripts to tell us ++ * the device's physical major and minor numbers. Switch to InitWait. ++ */ ++#define VERSION_SZ 4 ++static int usbback_probe(struct xenbus_device *dev, ++ const struct xenbus_device_id *id) ++{ ++ int err; ++ char version[VERSION_SZ]; ++ struct backend_info *be = kzalloc(sizeof(struct backend_info), ++ GFP_KERNEL); ++ if (!be) { ++ xenbus_dev_fatal(dev, -ENOMEM, ++ "allocating backend structure"); ++ return -ENOMEM; ++ } ++ be->dev = dev; ++ dev_set_drvdata(&dev->dev, be); ++ ++ be->usbif = usbif_alloc(dev->otherend_id); ++ if (IS_ERR(be->usbif)) { ++ err = PTR_ERR(be->usbif); ++ be->usbif = NULL; ++ xenbus_dev_fatal(dev, err, "creating block interface"); ++ goto fail; ++ } ++ ++ /* setup back pointer */ ++ be->usbif->be = be; ++ ++ err = xenbus_watch_pathfmt(dev, &be->backend_watch, NULL, backend_changed, ++ "%s/%s", dev->nodename, "physical-device"); ++ if (err) ++ goto fail; ++ ++ err = xenbus_watch_pathfmt(dev, &be->autosuspend_watch, NULL, ++ autosuspend_changed, "%s/%s", dev->otherend, ++ "autosuspend"); ++ if (err) ++ goto fail; ++ ++ debug_print(LOG_LVL_ERROR, "Setup watch for %s/%s\n", dev->otherend, "autosuspend"); ++ ++ err = snprintf(version, VERSION_SZ, "%d", USBBCK_VERSION); ++ if (err < 0) ++ goto fail; ++ ++ err = xenbus_write(XBT_NIL, dev->nodename, "version", version); ++ if (err) ++ goto fail; ++ ++ err = xenbus_switch_state(dev, XenbusStateInitWait); ++ if (err) ++ goto fail; ++ ++ return 0; ++ ++fail: ++ debug_print(LOG_LVL_ERROR, "Probe failed\n"); ++ usbback_remove(dev); ++ return err; ++} ++ ++/** ++ * Callback received when the frontend's state changes. ++ */ ++static void frontend_changed(struct xenbus_device *dev, ++ enum xenbus_state frontend_state) ++{ ++ struct backend_info *be = dev_get_drvdata(&dev->dev); ++ int err; ++ ++ debug_print(LOG_LVL_INFO, "Frontend state: %s Backend state: %s\n", ++ xenbus_strstate(frontend_state), xenbus_strstate(dev->state)); ++ ++ switch (frontend_state) { ++ case XenbusStateInitialising: ++ if (dev->state == XenbusStateClosed) { ++ printk(KERN_INFO "%s: %s: prepare for reconnect\n", ++ __FUNCTION__, dev->nodename); ++ xenbus_switch_state(dev, XenbusStateInitWait); ++ } ++ break; ++ ++ case XenbusStateInitialised: ++ case XenbusStateConnected: ++ /* Ensure we connect even when two watches fire in ++ close successsion and we miss the intermediate value ++ of frontend_state. */ ++ if (dev->state == XenbusStateConnected) ++ break; ++ ++ err = connect_ring(be); ++ if (err) ++ break; ++ update_usbif_status(be->usbif); ++ break; ++ ++ case XenbusStateClosing: ++ usbif_disconnect(be->usbif, be->dev); ++ xenbus_switch_state(dev, XenbusStateClosing); ++ break; ++ ++ case XenbusStateClosed: ++ xenbus_switch_state(dev, XenbusStateClosed); ++ if (xenbus_dev_is_online(dev)) ++ break; ++ /* fall through if not online */ ++ fallthrough; ++ case XenbusStateUnknown: ++ device_unregister(&dev->dev); ++ break; ++ ++ default: ++ xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend", ++ frontend_state); ++ break; ++ } ++} ++ ++ ++/* ** Connection ** */ ++ ++ ++/** ++ * Write the physical details regarding the usb device to the store, and ++ * switch to Connected state. ++ */ ++static void connect(struct backend_info *be) ++{ ++ struct xenbus_transaction xbt; ++ int err; ++ struct xenbus_device *dev = be->dev; ++ ++ debug_print(LOG_LVL_INFO, "Connect: %s\n", dev->otherend); ++ ++ /* Supply the information about the device the frontend needs */ ++again: ++ err = xenbus_transaction_start(&xbt); ++ if (err) { ++ xenbus_dev_fatal(dev, err, "starting transaction"); ++ return; ++ } ++ ++ err = usbback_barrier(xbt, be, 1); ++ if (err) ++ goto abort; ++ ++ err = xenbus_transaction_end(xbt, 0); ++ if (err == -EAGAIN) ++ goto again; ++ if (err) ++ xenbus_dev_fatal(dev, err, "ending transaction"); ++ ++ err = xenbus_switch_state(dev, XenbusStateConnected); ++ if (err) ++ xenbus_dev_fatal(dev, err, "switching to Connected state"); ++ ++ return; ++ abort: ++ xenbus_transaction_end(xbt, 1); ++} ++ ++static int connect_ring(struct backend_info *be) ++{ ++ struct xenbus_device *dev = be->dev; ++ grant_ref_t ring_ref; ++ unsigned int evtchn; ++ unsigned int version; ++ char protocol[64] = ""; ++ int err; ++ ++ debug_print(LOG_LVL_INFO, "Connect ring: %s\n", dev->otherend); ++ ++ err = xenbus_scanf(XBT_NIL, dev->otherend, "version", "%d", ++ &version); ++ if (XENBUS_EXIST_ERR(err)) { ++ debug_print(LOG_LVL_ERROR, "frontend version doesn't exist, must be old\n"); ++ return -1; ++ } ++ if (err != 1) { ++ xenbus_dev_fatal(dev, err, "reading version"); ++ return -1; ++ } ++ debug_print(LOG_LVL_INFO, "frontend version %d\n", version); ++ if (version < USBBCK_VERSION) { ++ xenbus_dev_fatal(dev, EINVAL, "frontend doesn't match backend (%d)", version); ++ return -1; ++ } ++ ++ err = xenbus_gather(XBT_NIL, dev->otherend, "ring-ref", "%lu", &ring_ref, ++ "event-channel", "%u", &evtchn, NULL); ++ if (err) { ++ xenbus_dev_fatal(dev, err, ++ "reading %s/ring-ref and event-channel", ++ dev->otherend); ++ return err; ++ } ++ ++ be->usbif->usb_protocol = USBIF_PROTOCOL_NATIVE; ++ err = xenbus_gather(XBT_NIL, dev->otherend, "protocol", ++ "%63s", protocol, NULL); ++ if (err) { ++ strcpy(protocol, "unspecified"); ++// be->usbif->usb_protocol = xen_guest_usbif_protocol(be->usbif->domid); ++ } ++ else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_NATIVE)) ++ be->usbif->usb_protocol = USBIF_PROTOCOL_NATIVE; ++ else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_32)) ++ be->usbif->usb_protocol = USBIF_PROTOCOL_X86_32; ++ else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_64)) ++ be->usbif->usb_protocol = USBIF_PROTOCOL_X86_64; ++ else { ++ xenbus_dev_fatal(dev, err, "unknown fe protocol %s", protocol); ++ return -1; ++ } ++ debug_print(LOG_LVL_INFO, ++ "usbback: ring-ref %d, event-channel %d, protocol %d (%s)\n", ++ ring_ref, evtchn, be->usbif->usb_protocol, protocol); ++ ++ /* Map the shared frame, irq etc. */ ++ err = usbif_map(be->usbif, ring_ref, evtchn); ++ if (err) { ++ xenbus_dev_fatal(dev, err, "mapping ring-ref %d port %u", ++ ring_ref, evtchn); ++ return err; ++ } ++ ++ return 0; ++} ++ ++ ++/* ++ * Driver Registration ++ */ ++static const struct xenbus_device_id usbback_ids[] = { ++ { "vusb" }, ++ { "" } ++}; ++ ++static struct xenbus_driver usbback_driver = { ++ .name = "usbback", ++ .ids = usbback_ids, ++ .probe = usbback_probe, ++ .remove = usbback_remove, ++ .otherend_changed = frontend_changed ++}; ++ ++int usbif_xenbus_init(void) ++{ ++ return xenbus_register_backend(&usbback_driver); ++} +--- /dev/null ++++ b/include/linux/dusb.h +@@ -0,0 +1,44 @@ ++/*****************************************************************************/ ++ ++/* ++ * dusb.c -- Direct communication with USB devices. ++ * ++ * Copyright (C) 1999-2000 Thomas Sailer (sailer@ife.ee.ethz.ch) ++ * Copyright (C) 2008-2012 Virtual Computer Inc ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * ++ * Derived from usb/core/devio.c ++ * ++ */ ++ ++/*****************************************************************************/ ++ ++#ifndef __LINUX_DUSB_H ++#define __LINUX_DUSB_H ++ ++extern struct usb_device *dusb_open(unsigned bus, unsigned device); ++extern void dusb_close(struct usb_device *dev); ++extern int dusb_set_configuration(struct usb_device *dev, int configuration); ++extern void dusb_flush_endpoint(struct usb_device *udev, struct usb_host_endpoint *ep); ++ ++extern int dusb_dev_running(struct usb_device *udev); ++extern int dusb_dev_controller_speed(struct usb_device *udev); ++ ++/* hub.c */ ++extern void usb_device_reenumerate(struct usb_device *udev); ++ ++#endif +--- /dev/null ++++ b/include/xen/interface/io/usbif.h +@@ -0,0 +1,196 @@ ++/****************************************************************************** ++ * usbif.h ++ * ++ * Unified usb-device I/O interface for Xen guest OSes. ++ * ++ * 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. ++ * ++ * Derived from blkif.h ++ * ++ * Copyright (c) 2003-2004, Keir Fraser ++ * Copyright (c) 2008, Virtual Computer Inc. ++ */ ++ ++#ifndef __XEN_PUBLIC_IO_USBIF_H__ ++#define __XEN_PUBLIC_IO_USBIF_H__ ++ ++#include "ring.h" ++#include "../grant_table.h" ++ ++/* ++ * Front->back notifications: When enqueuing a new request, sending a ++ * notification can be made conditional on req_event (i.e., the generic ++ * hold-off mechanism provided by the ring macros). Backends must set ++ * req_event appropriately (e.g., using RING_FINAL_CHECK_FOR_REQUESTS()). ++ * ++ * Back->front notifications: When enqueuing a new response, sending a ++ * notification can be made conditional on rsp_event (i.e., the generic ++ * hold-off mechanism provided by the ring macros). Frontends must set ++ * rsp_event appropriately (e.g., using RING_FINAL_CHECK_FOR_RESPONSES()). ++ */ ++ ++#ifndef usbif_vdev_t ++#define usbif_vdev_t uint16_t ++#endif ++ ++/* URB operations */ ++#define USBIF_T_CNTRL 0 ++#define USBIF_T_ISOC 1 ++#define USBIF_T_BULK 2 ++#define USBIF_T_INT 3 ++ ++/* non URB operations */ ++#define USBIF_T_RESET 4 ++#define USBIF_T_ABORT_PIPE 5 ++#define USBIF_T_GET_FRAME 6 ++#define USBIF_T_GET_SPEED 7 ++#define USBIF_T_CANCEL 8 ++ ++#define USBIF_T_MAX (USBIF_T_CANCEL) ++ ++#define USBIF_F_SHORTOK 0x01 ++#define USBIF_F_RESET 0x02 ++#define USBIF_F_ASAP 0x04 /* start ISO request on next available frame */ ++#define USBIF_F_INDIRECT 0x08 /* this request contains indirect segments */ ++#define USBIF_F_CYCLE_PORT 0x10 /* force re-enumeration of this device */ ++#define USBIF_F_DIRECT_DATA 0x20 /* request contains data directly inline */ ++ ++/* ++ * Maximum scatter/gather segments per request. ++ * This is carefully chosen so that sizeof(usbif_ring_t) <= PAGE_SIZE. ++ * NB. ++ */ ++#define USBIF_MAX_SEGMENTS_PER_REQUEST 17 ++#define USBIF_MAX_ISO_SEGMENTS (USBIF_MAX_SEGMENTS_PER_REQUEST - 1) ++ ++typedef uint32_t usbif_request_len_t; ++ ++struct usbif_request { ++ uint64_t id; /* private guest value, echoed in resp */ ++ uint64_t setup; ++ uint8_t type; /* USBIF_T_??? */ ++ uint8_t endpoint; ++ uint16_t offset; ++ usbif_request_len_t length; ++ uint8_t nr_segments; /* number of segments */ ++ uint8_t flags; ++ uint16_t nr_packets; /* number of ISO packets */ ++ uint32_t startframe; ++ union { ++ grant_ref_t gref[USBIF_MAX_SEGMENTS_PER_REQUEST]; ++ uint8_t data[sizeof(grant_ref_t)*USBIF_MAX_SEGMENTS_PER_REQUEST]; ++ } u; ++ uint32_t pad; ++}; ++typedef struct usbif_request usbif_request_t; ++ ++#define INDIRECT_SEGMENTS ++ ++#ifdef INDIRECT_SEGMENTS ++#define USBIF_MAX_SEGMENTS_PER_IREQUEST 1023 ++struct usbif_indirect_request { ++ uint32_t nr_segments; ++ grant_ref_t gref[USBIF_MAX_SEGMENTS_PER_IREQUEST]; ++}; ++typedef struct usbif_indirect_request usbif_indirect_request_t; ++#endif ++ ++struct usbif_iso_packet_info { ++ usbif_request_len_t offset; ++ uint16_t length; ++ uint16_t status; ++}; ++typedef struct usbif_iso_packet_info usbif_iso_packet_info_t; ++ ++struct usbif_response { ++ uint64_t id; /* copied from request */ ++ usbif_request_len_t actual_length; ++ uint32_t data; ++ int16_t status; /* USBIF_RSP_??? */ ++ uint32_t error_count; /* total ISOCH error count */ ++}; ++typedef struct usbif_response usbif_response_t; ++ ++/* ++ * STATUS RETURN CODES. ++ */ ++ /* USB errors */ ++#define USBIF_RSP_USB_ERROR -10 ++ ++#define USBIF_USB_CANCELED -1 ++#define USBIF_RSP_USB_CANCELED (USBIF_RSP_USB_ERROR + USBIF_USB_CANCELED) ++#define USBIF_USB_PENDING -2 ++#define USBIF_RSP_USB_PENDING (USBIF_RSP_USB_ERROR + USBIF_USB_PENDING) ++#define USBIF_USB_PROTO -3 ++#define USBIF_RSP_USB_PROTO (USBIF_RSP_USB_ERROR + USBIF_USB_PROTO) ++#define USBIF_USB_CRC -4 ++#define USBIF_RSP_USB_CRC (USBIF_RSP_USB_ERROR + USBIF_USB_CRC) ++#define USBIF_USB_TIMEOUT -5 ++#define USBIF_RSP_USB_TIMEOUT (USBIF_RSP_USB_ERROR + USBIF_USB_TIMEOUT) ++#define USBIF_USB_STALLED -6 ++#define USBIF_RSP_USB_STALLED (USBIF_RSP_USB_ERROR + USBIF_USB_STALLED) ++#define USBIF_USB_INBUFF -7 ++#define USBIF_RSP_USB_INBUFF (USBIF_RSP_USB_ERROR + USBIF_USB_INBUFF) ++#define USBIF_USB_OUTBUFF -8 ++#define USBIF_RSP_USB_OUTBUFF (USBIF_RSP_USB_ERROR + USBIF_USB_OUTBUFF) ++#define USBIF_USB_OVERFLOW -9 ++#define USBIF_RSP_USB_OVERFLOW (USBIF_RSP_USB_ERROR + USBIF_USB_OVERFLOW) ++#define USBIF_USB_SHORTPKT -10 ++#define USBIF_RSP_USB_SHORTPKT (USBIF_RSP_USB_ERROR + USBIF_USB_SHORTPKT) ++#define USBIF_USB_DEVRMVD -11 ++#define USBIF_RSP_USB_DEVRMVD (USBIF_RSP_USB_ERROR + USBIF_USB_DEVRMVD) ++#define USBIF_USB_PARTIAL -12 ++#define USBIF_RSP_USB_PARTIAL (USBIF_RSP_USB_ERROR + USBIF_USB_PARTIAL) ++#define USBIF_USB_INVALID -13 ++#define USBIF_RSP_USB_INVALID (USBIF_RSP_USB_ERROR + USBIF_USB_INVALID) ++#define USBIF_USB_RESET -14 ++#define USBIF_RSP_USB_RESET (USBIF_RSP_USB_ERROR + USBIF_USB_RESET) ++#define USBIF_USB_SHUTDOWN -15 ++#define USBIF_RSP_USB_SHUTDOWN (USBIF_RSP_USB_ERROR + USBIF_USB_SHUTDOWN) ++#define USBIF_USB_UNKNOWN -16 ++#define USBIF_RSP_USB_UNKNOWN (USBIF_RSP_USB_ERROR + USBIF_USB_UNKNOWN) ++ ++ /* Operation not supported. */ ++#define USBIF_RSP_EOPNOTSUPP -2 ++ /* Operation failed for some unspecified reason (-EIO). */ ++#define USBIF_RSP_ERROR -1 ++ /* Operation completed successfully. */ ++#define USBIF_RSP_OKAY 0 ++ ++#define USBIF_S_LOW 1 ++#define USBIF_S_FULL 2 ++#define USBIF_S_HIGH 3 ++ ++/* ++ * Generate usbif ring structures and types. ++ */ ++ ++DEFINE_RING_TYPES(usbif, struct usbif_request, struct usbif_response); ++ ++#endif /* __XEN_PUBLIC_IO_USBIF_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +--- /dev/null ++++ b/include/xen/vusb.h +@@ -0,0 +1,56 @@ ++#ifndef __XEN_VUSB_H__ ++#define __XEN_VUSB_H__ ++ ++#include ++#include ++#include ++ ++/* Not a real protocol. Used to generate ring structs which contain ++ * the elements common to all protocols only. This way we get a ++ * compiler-checkable way to use common struct elements, so we can ++ * avoid using switch(protocol) in a number of places. */ ++struct usbif_common_request { ++ char dummy; ++}; ++struct usbif_common_response { ++ char dummy; ++}; ++ ++/* i386 protocol version */ ++typedef struct usbif_request usbif_x86_32_request_t; ++typedef struct usbif_response usbif_x86_32_response_t; ++ ++ ++/* x86_64 protocol version */ ++typedef struct usbif_request usbif_x86_64_request_t; ++typedef struct usbif_response usbif_x86_64_response_t; ++ ++DEFINE_RING_TYPES(usbif_common, struct usbif_common_request, struct usbif_common_response); ++DEFINE_RING_TYPES(usbif_x86_32, struct usbif_request, struct usbif_response); ++DEFINE_RING_TYPES(usbif_x86_64, struct usbif_request, struct usbif_response); ++ ++union usbif_back_rings { ++ struct usbif_back_ring native; ++ struct usbif_common_back_ring common; ++ struct usbif_x86_32_back_ring x86_32; ++ struct usbif_x86_64_back_ring x86_64; ++}; ++typedef union usbif_back_rings usbif_back_rings_t; ++ ++enum usbif_protocol { ++ USBIF_PROTOCOL_NATIVE = 1, ++ USBIF_PROTOCOL_X86_32 = 2, ++ USBIF_PROTOCOL_X86_64 = 3, ++}; ++ ++static void inline usbif_get_x86_32_req(usbif_request_t *dst, usbif_x86_32_request_t *src) ++{ ++ memcpy(dst, src, sizeof(usbif_request_t)); ++} ++ ++static void inline usbif_get_x86_64_req(usbif_request_t *dst, usbif_x86_64_request_t *src) ++{ ++ memcpy(dst, src, sizeof(usbif_request_t)); ++} ++ ++#endif /* __XEN_VUSB_H__ */ diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-video-quirks/acpi-video-delay-init.patch b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-video-quirks/acpi-video-delay-init.patch new file mode 100644 index 0000000000..a7d4910fdf --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-video-quirks/acpi-video-delay-init.patch @@ -0,0 +1,92 @@ +################################################################################ +SHORT DESCRIPTION: +################################################################################ +Add cmdline option "delay_init" to force acpi_video_register early on even if +intel opregion is detected on the system. + +################################################################################ +LONG DESCRIPTION: +################################################################################ +This sounds dangerous at best since for old hardware (sandy-bridge and before?) +with an acpi opregion, acpi_video_register() is explicitely by-passed in +acpi_video_init(). + +################################################################################ +CHANGELOG +################################################################################ +Port to 3.18: Eric Chanudet +Port to 4.14: Richard Turner + +################################################################################ +REMOVAL +################################################################################ +Recommended for removal unless we figure out why this is in here. + +################################################################################ +UPSTREAM PLAN +################################################################################ +None, upstream clearly does something different. + +################################################################################ +INTERNAL DEPENDENCIES +################################################################################ +xenclient-dom0-tweak adds delay_init on grub's kernel cmdline. + +################################################################################ +PATCHES +################################################################################ +--- a/drivers/acpi/acpi_video.c ++++ b/drivers/acpi/acpi_video.c +@@ -76,6 +76,9 @@ module_param(device_id_scheme, bool, 044 + static int only_lcd = -1; + module_param(only_lcd, int, 0444); + ++static bool delay_init = 0; ++module_param(delay_init, bool, 0644); ++ + static int register_count; + static DEFINE_MUTEX(register_count_mutex); + static DEFINE_MUTEX(video_list_lock); +@@ -2258,6 +2261,22 @@ bool acpi_video_handles_brightness_key_p + } + EXPORT_SYMBOL(acpi_video_handles_brightness_key_presses); + ++static ssize_t store_init_acpi_video(struct bus_type *bus, ++ const char *buf, size_t count) ++{ ++ unsigned int val; ++ if (kstrtouint(buf, 10, &val) || val != 1) ++ return -EINVAL; ++ acpi_video_register(); ++ return count; ++} ++ ++static struct bus_attribute init_acpi_video_attr = { ++ .attr = {.name = "init_acpi_video", .mode = 0644}, ++ .show = NULL, ++ .store = store_init_acpi_video, ++}; ++ + /* + * This is kind of nasty. Hardware using Intel chipsets may require + * the video opregion code to be run first in order to initialise +@@ -2278,6 +2297,9 @@ static int __init acpi_video_init(void) + if (acpi_disabled) + return 0; + ++ if (delay_init) ++ return bus_create_file(&acpi_bus_type, &init_acpi_video_attr); ++ + if (intel_opregion_present()) + return 0; + +@@ -2286,6 +2308,9 @@ static int __init acpi_video_init(void) + + static void __exit acpi_video_exit(void) + { ++ if (delay_init) ++ bus_remove_file(&acpi_bus_type, &init_acpi_video_attr); ++ + acpi_video_detect_exit(); + acpi_video_unregister(); + diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-video-quirks/openxt-video-quirks.scc b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-video-quirks/openxt-video-quirks.scc new file mode 100644 index 0000000000..80fd082688 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-video-quirks/openxt-video-quirks.scc @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: MIT +define KFEATURE_DESCRIPTION "Apply OpenXT video quirks." +define KFEATURE_COMPATIBILITY board + +# Cmdline option to force acpi_video_register() to run early, even when it presumably should not. +## TODO: determine if this is necessary. +#patch acpi-video-delay-init.patch + +# Give additional flags to /dev/mem mmap'ed memory (surfman?) +## TODO: determine if this is necessary. +#patch realmem-mmap.patch diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-video-quirks/realmem-mmap.patch b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-video-quirks/realmem-mmap.patch new file mode 100644 index 0000000000..87d2f877f2 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-video-quirks/realmem-mmap.patch @@ -0,0 +1,57 @@ +################################################################################ +SHORT DESCRIPTION: +################################################################################ +Give additional flags to /dev/mem mmap()'ed pages. + +################################################################################ +LONG DESCRIPTION: +################################################################################ +Force VM_SPECIAL (special vmas that are non-mergable, non-mlock()able) and +VM_DONTDUMP (Do not include in the core dump) flags on pages mapped using +/dev/mem char device. + +################################################################################ +CHANGELOG +################################################################################ +Original author: unknown +Port to 3.18: Eric Chanudet +Port to 4.14: Richard Turner +Port to 4.19: Richard Turner + +################################################################################ +REMOVAL +################################################################################ +? + +################################################################################ +UPSTREAM PLAN +################################################################################ +None. + +################################################################################ +INTERNAL DEPENDENCIES +################################################################################ +? + +################################################################################ +PATCHES +################################################################################ +--- a/drivers/char/mem.c ++++ b/drivers/char/mem.c +@@ -396,9 +396,13 @@ static int mmap_mem(struct file *file, s + &vma->vm_page_prot)) + return -EINVAL; + +- vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_pgoff, +- size, +- vma->vm_page_prot); ++ vma->vm_flags |= VM_DONTDUMP | VM_SPECIAL; ++ vma->vm_page_prot = __pgprot( ++ pgprot_val(vm_get_page_prot(vma->vm_flags)) | ++ pgprot_val(phys_mem_access_prot(file, ++ vma->vm_pgoff, ++ size, ++ vma->vm_page_prot))); + + vma->vm_ops = &mmap_mem_ops; + diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-vwif/netback-vwif-support.patch b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-vwif/netback-vwif-support.patch new file mode 100644 index 0000000000..1a2d1ecd90 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-vwif/netback-vwif-support.patch @@ -0,0 +1,10 @@ +--- a/drivers/net/xen-netback/xenbus.c ++++ b/drivers/net/xen-netback/xenbus.c +@@ -1134,6 +1134,7 @@ static int read_xenbus_vif_flags(struct + + static const struct xenbus_device_id netback_ids[] = { + { "vif" }, ++ { "vwif" }, + { "" } + }; + diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-vwif/openxt-vwif.scc b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-vwif/openxt-vwif.scc new file mode 100644 index 0000000000..5d2efc8266 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/openxt-vwif/openxt-vwif.scc @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: MIT +define KFEATURE_DESCRIPTION "OpenXT VWIF PV wireless device." +define KFEATURE_COMPATIBILITY all + +# Add "vwif" as a xenbus netback ID. +patch netback-vwif-support.patch diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/xen-txt/0001-txt_info-expose-TXT-conf-registers-to-userland.patch b/recipes-kernel/linux/files/openxt-kmeta/patches/xen-txt/0001-txt_info-expose-TXT-conf-registers-to-userland.patch new file mode 100644 index 0000000000..07f8faba86 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/xen-txt/0001-txt_info-expose-TXT-conf-registers-to-userland.patch @@ -0,0 +1,227 @@ +From acff0fec046e730871aa7342fe8118479eb092d2 Mon Sep 17 00:00:00 2001 +From: Eric Chanudet +Date: Wed, 23 Jun 2021 10:12:42 -0400 +Subject: [PATCH] txt_info: expose TXT conf registers to userland + +TXT exposes configuration registers documented in its Software +Development Guide. Accessing these registers in sometimes necessary for +userland software to perform checks and validate compatibility with +software resources. + +Expose the previously mentioned resources through a platform device +driver in the sysfs. + +Signed-off-by: Eric Chanudet +--- + drivers/misc/Kconfig | 10 +++ + drivers/misc/Makefile | 1 + + drivers/misc/txt_info.c | 167 ++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 178 insertions(+) + create mode 100644 drivers/misc/txt_info.c + +diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig +index c55b63750757..2d3479593610 100644 +--- a/drivers/misc/Kconfig ++++ b/drivers/misc/Kconfig +@@ -466,6 +466,16 @@ config PVPANIC + a paravirtualized device provided by QEMU; it lets a virtual machine + (guest) communicate panic events to the host. + ++config TXT_INFO ++ tristate "Add TXT configuration registers in securityfs" ++ depends on X86 && TCG_TPM ++ default n ++ help ++ Expose the values of TXT configuration registers via the sysfs for ++ use in userland. To compile this as a module choose M. ++ ++ If unsure, say N. ++ + source "drivers/misc/c2port/Kconfig" + source "drivers/misc/eeprom/Kconfig" + source "drivers/misc/cb710/Kconfig" +diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile +index c1860d35dc7e..4ebacab15df2 100644 +--- a/drivers/misc/Makefile ++++ b/drivers/misc/Makefile +@@ -57,3 +57,4 @@ obj-y += cardreader/ + obj-$(CONFIG_PVPANIC) += pvpanic.o + obj-$(CONFIG_HABANA_AI) += habanalabs/ + obj-$(CONFIG_XILINX_SDFEC) += xilinx_sdfec.o ++obj-$(CONFIG_TXT_INFO) += txt_info.o +diff --git a/drivers/misc/txt_info.c b/drivers/misc/txt_info.c +new file mode 100644 +index 000000000000..ebece6a50612 +--- /dev/null ++++ b/drivers/misc/txt_info.c +@@ -0,0 +1,167 @@ ++#include ++#include ++#include ++#include ++#include ++ ++#define TXT_PUB_CR_BASE 0xfed30000 ++#define TXT_PUB_CR_SIZE 0x10000 ++static const struct resource txt_resources[] = { ++ { ++ .start = TXT_PUB_CR_BASE, ++ .end = TXT_PUB_CR_BASE + TXT_PUB_CR_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++}; ++#define TXT_PUB_CR_INDEX 0 ++ ++struct platform_device *pdev; ++struct txt_info { ++ void __iomem *cr_pub; ++ void __iomem *cr_priv; ++}; ++static struct txt_info txt_info; ++ ++static void __iomem *txt_info_map_regs(struct platform_device *pdev, ++ size_t index) ++{ ++ struct resource *res; ++ void __iomem *base; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, index); ++ if (IS_ERR(res)) { ++ dev_dbg(&pdev->dev, ++ "Failed to access IOMEM resource %zu.\n", index); ++ return res; ++ } ++ ++ base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); ++ if (IS_ERR(base)) ++ dev_dbg(&pdev->dev, ++ "Failed to ioremap configuration registers.\n"); ++ ++ return base; ++} ++ ++/* Registers offset from TXT_PUB_CR_BASE */ ++#define TXT_STS_OFFSET 0x000 ++#define TXT_ESTS_OFFSET 0x008 ++#define TXT_ERRORCODE_OFFSET 0x030 ++#define TXT_VER_FSBIF_OFFSET 0x100 ++#define TXT_DIDVID_OFFSET 0x110 ++#define TXT_VER_QPIIF_OFFSET 0x200 ++ ++#define DECLARE_PUB_SHOW_U8(name, offset) \ ++static ssize_t name##_show(struct kobject *kobj, \ ++ struct kobj_attribute *attr, char *buf) \ ++{ \ ++ uint8_t v = ioread8(txt_info.cr_pub + (offset)); \ ++ return sprintf(buf, "%#04x\n", v); \ ++} \ ++static struct kobj_attribute txt_attr_##name = __ATTR_RO(name); ++ ++#define DECLARE_PUB_SHOW_U32(name, offset) \ ++static ssize_t name##_show(struct kobject *kobj, \ ++ struct kobj_attribute *attr, char *buf) \ ++{ \ ++ uint32_t v = ioread32(txt_info.cr_pub + (offset)); \ ++ return sprintf(buf, "%#010x\n", v); \ ++} \ ++static struct kobj_attribute txt_attr_##name = __ATTR_RO(name); ++ ++#define DECLARE_PUB_SHOW_U64(name, offset) \ ++static ssize_t name##_show(struct kobject *kobj, \ ++ struct kobj_attribute *attr, char *buf) \ ++{ \ ++ uint64_t v = ioread32(txt_info.cr_pub + (offset) + 0x4); \ ++ v <<= 32; \ ++ v |= ioread32(txt_info.cr_pub + (offset)); \ ++ return sprintf(buf, "%#018llx\n", v); \ ++} \ ++static struct kobj_attribute txt_attr_##name = __ATTR_RO(name); ++ ++DECLARE_PUB_SHOW_U64(sts, TXT_STS_OFFSET); ++DECLARE_PUB_SHOW_U8(ests, TXT_ESTS_OFFSET); ++DECLARE_PUB_SHOW_U32(errorcode, TXT_ERRORCODE_OFFSET); ++DECLARE_PUB_SHOW_U32(ver_fsbif, TXT_VER_FSBIF_OFFSET); ++DECLARE_PUB_SHOW_U64(didvid, TXT_DIDVID_OFFSET); ++DECLARE_PUB_SHOW_U32(ver_qpiif, TXT_VER_QPIIF_OFFSET); ++ ++static struct attribute *txt_subsys_attrs[] = { ++ &txt_attr_sts.attr, ++ &txt_attr_ests.attr, ++ &txt_attr_errorcode.attr, ++ &txt_attr_ver_fsbif.attr, ++ &txt_attr_didvid.attr, ++ &txt_attr_ver_qpiif.attr, ++ NULL, ++}; ++ ++static umode_t txt_attr_is_visible(struct kobject *kobj, ++ struct attribute *attr, int n) ++{ ++ return attr->mode; ++} ++ ++static const struct attribute_group txt_subsys_attr_group = { ++ .attrs = txt_subsys_attrs, ++ .is_visible = txt_attr_is_visible, ++}; ++ ++struct kobject *txt_kobj; ++ ++static int __init init_txt_info(void) ++{ ++ int rc; ++ void __iomem *base; ++ ++ pr_info("%s\n", __func__); ++ ++ pdev = platform_device_register_simple( ++ "txt", -1, txt_resources, ARRAY_SIZE(txt_resources)); ++ if (IS_ERR(pdev)) { ++ rc = PTR_ERR(pdev); ++ pr_err("Failed to register txt platform device driver (%d).\n", rc); ++ goto fail_register; ++ } ++ ++ base = txt_info_map_regs(pdev, TXT_PUB_CR_INDEX); ++ if (IS_ERR(base)) { ++ rc = PTR_ERR(base); ++ dev_err(&pdev->dev, ++ "Failed to map TXT public resources (%d).\n", rc); ++ goto fail_map_pub; ++ } ++ txt_info.cr_pub = base; ++ ++ rc = sysfs_create_group(&pdev->dev.kobj, &txt_subsys_attr_group); ++ if (rc) { ++ dev_err(&pdev->dev, "Failed to create sysfs group (%d).\n", rc); ++ goto fail_sysfs; ++ } ++ ++ return 0; ++ ++fail_sysfs: ++ devm_iounmap(&pdev->dev, txt_info.cr_pub); ++fail_map_pub: ++ platform_device_unregister(pdev); ++fail_register: ++ return rc; ++} ++ ++static void __exit cleanup_txt_info(void) ++{ ++ pr_info("%s\n", __func__); ++ ++ if (pdev) ++ platform_device_unregister(pdev); ++} ++ ++module_init(init_txt_info); ++module_exit(cleanup_txt_info); ++ ++MODULE_AUTHOR("Assured Information Security, Inc"); ++MODULE_DESCRIPTION("TXT driver."); ++MODULE_VERSION("1.0"); ++MODULE_LICENSE("GPL"); +-- +2.17.1 + diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/xen-txt/xen-txt-add-xen-txt-eventlog-module.patch b/recipes-kernel/linux/files/openxt-kmeta/patches/xen-txt/xen-txt-add-xen-txt-eventlog-module.patch new file mode 100644 index 0000000000..0b2642e4de --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/xen-txt/xen-txt-add-xen-txt-eventlog-module.patch @@ -0,0 +1,303 @@ +From fee3e4a2677f133a45f2b9bea40c8d7715f58b16 Mon Sep 17 00:00:00 2001 +From: "Daniel P. Smith" +Date: Thu, 18 May 2017 17:48:52 -0400 +Subject: [PATCH] xen-txt: add xen txt eventlog module + +--- + arch/x86/include/asm/xen/hypercall.h | 6 ++ + drivers/xen/Kconfig | 7 ++ + drivers/xen/Makefile | 1 + + drivers/xen/txt.c | 200 +++++++++++++++++++++++++++++++++++ + include/xen/interface/xen.h | 8 ++ + 5 files changed, 222 insertions(+) + create mode 100644 drivers/xen/txt.c + +--- a/arch/x86/include/asm/xen/hypercall.h ++++ b/arch/x86/include/asm/xen/hypercall.h +@@ -446,6 +446,12 @@ HYPERVISOR_dm_op( + return ret; + } + ++static inline int ++HYPERVISOR_txt_op(unsigned int op, void *arg) ++{ ++ return _hypercall2(int, txt_op, op, arg); ++} ++ + static inline void + MULTI_fpu_taskswitch(struct multicall_entry *mcl, int set) + { +--- a/drivers/xen/Kconfig ++++ b/drivers/xen/Kconfig +@@ -177,6 +177,15 @@ config SWIOTLB_XEN + def_bool y + select SWIOTLB + ++config XEN_TXT ++ tristate "Xen TXT event log retrieval" ++ depends on X86 && TCG_TPM ++ default n ++ help ++ Support the Xen hypercall to retrieve the tboot TXT ++ event log. The log can be read through securityfs ++ txt/tpm12_binary_evtlog or txt/tpm20_binary_evtlog ++ + config XEN_PCIDEV_BACKEND + tristate "Xen PCI-device backend driver" + depends on PCI && X86 && XEN +--- a/drivers/xen/Makefile ++++ b/drivers/xen/Makefile +@@ -23,6 +23,7 @@ obj-$(CONFIG_XEN_GRANT_DEV_ALLOC) += xen + obj-$(CONFIG_XENFS) += xenfs/ + obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o + obj-$(CONFIG_XEN_PVHVM) += platform-pci.o ++obj-$(CONFIG_XEN_TXT) += txt.o + obj-$(CONFIG_SWIOTLB_XEN) += swiotlb-xen.o + obj-$(CONFIG_XEN_MCE_LOG) += mcelog.o + obj-$(CONFIG_XEN_PCIDEV_BACKEND) += xen-pciback/ +--- /dev/null ++++ b/drivers/xen/txt.c +@@ -0,0 +1,212 @@ ++/* ++ * Copyright (C) 2017 Apertus Solutions, LLC ++ * ++ * Authors: ++ * Daniel P. Smith ++ * ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#define FS_LOG_ENTRY 0 ++#define FS_DIR_ENTRY 1 /* must be last */ ++#define FS_ENTRIES 2 ++ ++static struct txt_op txt_log; ++static struct dentry *fs_entries[FS_ENTRIES]; ++ ++ ++#define TPM_LOG_BLOCK_SIZE 1024 ++ ++static void *tpm_evtlog_start(struct seq_file *m, loff_t *pos) ++{ ++ struct txt_op *log = m->private; ++ void *addr = log->buffer; ++ ++ addr += *pos * TPM_LOG_BLOCK_SIZE; ++ ++ if (addr > log->buffer + log->size) ++ return NULL; ++ ++ return addr; ++} ++ ++static void *tpm_evtlog_next(struct seq_file *m, void *v, loff_t *pos) ++{ ++ size_t size = 0; ++ struct txt_op *log = m->private; ++ void *addr = v; ++ ++ size = (log->buffer + log->size) - addr; ++ size = size > TPM_LOG_BLOCK_SIZE ? TPM_LOG_BLOCK_SIZE : size; ++ ++ if ((size == 0) || ++ ((addr + size) > (log->buffer + log->size))) ++ return NULL; ++ ++ addr += size; ++ (*pos)++; ++ ++ return addr; ++} ++ ++static void tpm_evtlog_stop(struct seq_file *m, void *v) ++{ ++} ++ ++static int tpm_evtlog_show(struct seq_file *m, void *v) ++{ ++ size_t size; ++ struct txt_op *log = m->private; ++ void *addr = v; ++ ++ size = ((log->buffer + log->size) - addr) > TPM_LOG_BLOCK_SIZE ? ++ TPM_LOG_BLOCK_SIZE : (log->buffer + log->size) - addr; ++ ++ if ((size != 0) && ++ ((addr + size) <= (log->buffer + log->size))) ++ seq_write(m, addr, size); ++ ++ return 0; ++} ++ ++const struct seq_operations tpm_evtlog_seqops = { ++ .start = tpm_evtlog_start, ++ .next = tpm_evtlog_next, ++ .stop = tpm_evtlog_stop, ++ .show = tpm_evtlog_show, ++}; ++ ++static int tpm_evtlog_open(struct inode *inode, struct file *file) ++{ ++ int err; ++ struct seq_file *seq; ++ ++ err = seq_open(file, &tpm_evtlog_seqops); ++ if (!err) { ++ seq = file->private_data; ++ seq->private = &txt_log; ++ } ++ ++ return err; ++} ++ ++static const struct file_operations tpm_evtlog_ops = { ++ .open = tpm_evtlog_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = seq_release, ++}; ++ ++ ++static long expose_evtlog(const char *name) ++{ ++ long ret = 0; ++ char *filename; ++ ++ fs_entries[FS_DIR_ENTRY] = securityfs_create_dir(name, NULL); ++ if (IS_ERR(fs_entries[FS_DIR_ENTRY])) { ++ ret = PTR_ERR(fs_entries[FS_DIR_ENTRY]); ++ goto out; ++ } ++ ++ switch (txt_log.format) { ++ case TXTOP_EVTLOG_FORMAT_TCG_12: ++ filename = "tpm12_binary_evtlog"; ++ break; ++ case TXTOP_EVTLOG_FORMAT_LEGACY_20: ++ filename = "tpm20_binary_evtlog_legacy"; ++ break; ++ case TXTOP_EVTLOG_FORMAT_TCG_20: ++ filename = "tpm20_binary_evtlog_tcg"; ++ break; ++ default: ++ printk(KERN_ERR "Incompatible event-log format: %x\n", txt_log.format); ++ ret = EINVAL; ++ goto out_dir; ++ } ++ ++ fs_entries[FS_LOG_ENTRY] = ++ securityfs_create_file(filename, ++ S_IRUSR | S_IRGRP, ++ fs_entries[FS_DIR_ENTRY], NULL, ++ &tpm_evtlog_ops); ++ if (IS_ERR(fs_entries[FS_LOG_ENTRY])) { ++ ret = PTR_ERR(fs_entries[FS_LOG_ENTRY]); ++ goto out_dir; ++ } ++ ++ return 0; ++ ++out_dir: ++ securityfs_remove(fs_entries[FS_DIR_ENTRY]); ++out: ++ return ret; ++} ++ ++void teardown_evtlog(void) ++{ ++ int i; ++ ++ for (i = 0; i < FS_ENTRIES; i++) ++ securityfs_remove(fs_entries[i]); ++} ++ ++static int __init txt_init(void) ++{ ++ int err; ++ ++ if (!xen_domain()) ++ return -ENODEV; ++ ++ txt_log.size = 0; ++ txt_log.buffer = NULL; ++ txt_log.format = 0; ++ if ((err = HYPERVISOR_txt_op(TXTOP_GET, &txt_log)) != 0) ++ return err; ++ ++ if (!txt_log.size) ++ return -ENODEV; ++ ++ txt_log.buffer = kmalloc(txt_log.size, GFP_KERNEL); ++ if (txt_log.buffer == NULL) ++ return -ENOMEM; ++ ++ if ((err = HYPERVISOR_txt_op(TXTOP_GET, &txt_log)) != 0) ++ goto error; ++ ++ if ((err = expose_evtlog("txt")) != 0) ++ goto error; ++ ++ return 0; ++ ++error: ++ kfree(txt_log.buffer); ++ return err; ++} ++ ++static void __exit txt_exit(void) ++{ ++ teardown_evtlog(); ++ ++ if (txt_log.buffer) ++ kfree(txt_log.buffer); ++} ++ ++module_init(txt_init); ++module_exit(txt_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Daniel P. Smith "); ++MODULE_DESCRIPTION("TXT TPM Event log"); +--- a/include/xen/interface/xen.h ++++ b/include/xen/interface/xen.h +@@ -82,6 +82,7 @@ + #define __HYPERVISOR_xc_reserved_op 39 /* reserved for XenClient */ + #define __HYPERVISOR_xenpmu_op 40 + #define __HYPERVISOR_dm_op 41 ++#define __HYPERVISOR_txt_op 42 + + /* Architecture-specific hypercall definitions. */ + #define __HYPERVISOR_arch_0 48 +@@ -745,6 +746,20 @@ typedef uint64_t cpumap_t; + + typedef uint8_t xen_domain_handle_t[16]; + ++#define TXTOP_GET 0 ++ ++struct txt_op { ++ uint64_t size; ++ ++#define TXTOP_EVTLOG_FORMAT_UNKNOWN 0x0 ++#define TXTOP_EVTLOG_FORMAT_TCG_12 0x1 ++#define TXTOP_EVTLOG_FORMAT_LEGACY_20 0x2 ++#define TXTOP_EVTLOG_FORMAT_TCG_20 0x3 ++ uint8_t format; ++ uint8_t _pad[7]; ++ void *buffer; ++}; ++ + /* Turn a plain number into a C unsigned long constant. */ + #define __mk_unsigned_long(x) x ## UL + #define mk_unsigned_long(x) __mk_unsigned_long(x) diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/xen-txt/xen-txt.cfg b/recipes-kernel/linux/files/openxt-kmeta/patches/xen-txt/xen-txt.cfg new file mode 100644 index 0000000000..46904f44b7 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/xen-txt/xen-txt.cfg @@ -0,0 +1,2 @@ +CONFIG_XEN_TXT=y +CONTIG_TXT_INFO=y diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/xen-txt/xen-txt.scc b/recipes-kernel/linux/files/openxt-kmeta/patches/xen-txt/xen-txt.scc new file mode 100644 index 0000000000..c8dca1c461 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/xen-txt/xen-txt.scc @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: MIT +define KFEATURE_DESCRIPTION "Expose TXT eventlog through securityfs." +define KFEATURE_COMPATIBILITY all + +# Use Xen custom hypercall to retrieve and expose the eventlog in the securityfs. +patch xen-txt-add-xen-txt-eventlog-module.patch +# Add a small platform device to expose TXT configuration registers in the securityfs. +patch 0001-txt_info-expose-TXT-conf-registers-to-userland.patch + +kconf hardware xen-txt.cfg diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/xsa-155/xsa-155-qsb-023-add-RING_COPY_RESPONSE.patch b/recipes-kernel/linux/files/openxt-kmeta/patches/xsa-155/xsa-155-qsb-023-add-RING_COPY_RESPONSE.patch new file mode 100644 index 0000000000..b6b5728697 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/xsa-155/xsa-155-qsb-023-add-RING_COPY_RESPONSE.patch @@ -0,0 +1,52 @@ +################################################################################ +SHORT DESCRIPTION: +################################################################################ +QSB-023 (https://github.com/QubesOS/qubes-secpack/blob/master/QSBs/qsb-023-2015) +XSA-155 additional patches for the Xen network and block frontends from Qubes +OS Project. + +################################################################################ +LONG DESCRIPTION: +################################################################################ +Source: https://github.com/QubesOS/qubes-linux-kernel/tree/stable-3.18/patches.xen +Patch: xsa155-linux-0008-xen-Add-RING_COPY_RESPONSE.patch + +Using RING_GET_RESPONSE() on a shared ring is easy to use incorrectly +(i.e., by not considering that the other end may alter the data in the +shared ring while it is being inspected). Safe usage of a response +generally requires taking a local copy. + +Provide a RING_COPY_RESPONSE() macro to use instead of +RING_GET_RESPONSE() and an open-coded memcpy(). This takes care of +ensuring that the copy is done correctly regardless of any possible +compiler optimizations. + +Use a volatile source to prevent the compiler from reordering or +omitting the copy. + +################################################################################ +PATCHES +################################################################################ +--- a/include/xen/interface/io/ring.h ++++ b/include/xen/interface/io/ring.h +@@ -201,6 +201,20 @@ struct __name##_back_ring { \ + #define RING_GET_RESPONSE(_r, _idx) \ + (&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].rsp)) + ++/* ++ * Get a local copy of a response. ++ * ++ * Use this in preference to RING_GET_RESPONSE() so all processing is ++ * done on a local copy that cannot be modified by the other end. ++ * ++ * Note that https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58145 may cause this ++ * to be ineffective where _rsp is a struct which consists of only bitfields. ++ */ ++#define RING_COPY_RESPONSE(_r, _idx, _rsp) do { \ ++ /* Use volatile to force the copy into _rsp. */ \ ++ *(_rsp) = *(volatile typeof(_rsp))RING_GET_RESPONSE(_r, _idx); \ ++} while (0) ++ + /* Loop termination condition: Would the specified index overflow the ring? */ + #define RING_REQUEST_CONS_OVERFLOW(_r, _cons) \ + (((_cons) - (_r)->rsp_prod_pvt) >= RING_SIZE(_r)) diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/xsa-155/xsa-155-qsb-023-xen-blkfront-make-local-copy-of-response-before-usin.patch b/recipes-kernel/linux/files/openxt-kmeta/patches/xsa-155/xsa-155-qsb-023-xen-blkfront-make-local-copy-of-response-before-usin.patch new file mode 100644 index 0000000000..76634baa46 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/xsa-155/xsa-155-qsb-023-xen-blkfront-make-local-copy-of-response-before-usin.patch @@ -0,0 +1,122 @@ +################################################################################ +SHORT DESCRIPTION: +################################################################################ +QSB-023 (https://github.com/QubesOS/qubes-secpack/blob/master/QSBs/qsb-023-2015) +XSA-155 additional patches for the Xen network and block frontends from Qubes +OS Project. + +################################################################################ +LONG DESCRIPTION: +################################################################################ +Source: https://github.com/QubesOS/qubes-linux-kernel/tree/stable-3.18/patches.xen +Patch: xsa155-linux312-0012-xen-blkfront-make-local-copy-of-response-before-usin.patch + +Data on the shared page can be changed at any time by the backend. Make +a local copy, which is no longer controlled by the backend. And only +then access it. + +################################################################################ +PATCHES +################################################################################ +--- a/drivers/block/xen-blkfront.c ++++ b/drivers/block/xen-blkfront.c +@@ -1549,7 +1549,7 @@ static bool blkif_completion(unsigned lo + static irqreturn_t blkif_interrupt(int irq, void *dev_id) + { + struct request *req; +- struct blkif_response *bret; ++ struct blkif_response bret; + RING_IDX i, rp; + unsigned long flags; + struct blkfront_ring_info *rinfo = (struct blkfront_ring_info *)dev_id; +@@ -1566,8 +1566,8 @@ static irqreturn_t blkif_interrupt(int i + for (i = rinfo->ring.rsp_cons; i != rp; i++) { + unsigned long id; + +- bret = RING_GET_RESPONSE(&rinfo->ring, i); +- id = bret->id; ++ RING_COPY_RESPONSE(&rinfo->ring, i, &bret); ++ id = bret.id; + /* + * The backend has messed up and given us an id that we would + * never have given to it (we stamp it up to BLK_RING_SIZE - +@@ -1575,39 +1575,39 @@ static irqreturn_t blkif_interrupt(int i + */ + if (id >= BLK_RING_SIZE(info)) { + WARN(1, "%s: response to %s has incorrect id (%ld)\n", +- info->gd->disk_name, op_name(bret->operation), id); ++ info->gd->disk_name, op_name(bret.operation), id); + /* We can't safely get the 'struct request' as + * the id is busted. */ + continue; + } + req = rinfo->shadow[id].request; + +- if (bret->operation != BLKIF_OP_DISCARD) { ++ if (bret.operation != BLKIF_OP_DISCARD) { + /* + * We may need to wait for an extra response if the + * I/O request is split in 2 + */ +- if (!blkif_completion(&id, rinfo, bret)) ++ if (!blkif_completion(&id, rinfo, &bret)) + continue; + } + + if (add_id_to_freelist(rinfo, id)) { + WARN(1, "%s: response to %s (id %ld) couldn't be recycled!\n", +- info->gd->disk_name, op_name(bret->operation), id); ++ info->gd->disk_name, op_name(bret.operation), id); + continue; + } + +- if (bret->status == BLKIF_RSP_OKAY) ++ if (bret.status == BLKIF_RSP_OKAY) + blkif_req(req)->error = BLK_STS_OK; + else + blkif_req(req)->error = BLK_STS_IOERR; + +- switch (bret->operation) { ++ switch (bret.operation) { + case BLKIF_OP_DISCARD: +- if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) { ++ if (unlikely(bret.status == BLKIF_RSP_EOPNOTSUPP)) { + struct request_queue *rq = info->rq; + printk(KERN_WARNING "blkfront: %s: %s op failed\n", +- info->gd->disk_name, op_name(bret->operation)); ++ info->gd->disk_name, op_name(bret.operation)); + blkif_req(req)->error = BLK_STS_NOTSUPP; + info->feature_discard = 0; + info->feature_secdiscard = 0; +@@ -1617,15 +1617,15 @@ static irqreturn_t blkif_interrupt(int i + break; + case BLKIF_OP_FLUSH_DISKCACHE: + case BLKIF_OP_WRITE_BARRIER: +- if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) { ++ if (unlikely(bret.status == BLKIF_RSP_EOPNOTSUPP)) { + printk(KERN_WARNING "blkfront: %s: %s op failed\n", +- info->gd->disk_name, op_name(bret->operation)); ++ info->gd->disk_name, op_name(bret.operation)); + blkif_req(req)->error = BLK_STS_NOTSUPP; + } +- if (unlikely(bret->status == BLKIF_RSP_ERROR && ++ if (unlikely(bret.status == BLKIF_RSP_ERROR && + rinfo->shadow[id].req.u.rw.nr_segments == 0)) { + printk(KERN_WARNING "blkfront: %s: empty %s op failed\n", +- info->gd->disk_name, op_name(bret->operation)); ++ info->gd->disk_name, op_name(bret.operation)); + blkif_req(req)->error = BLK_STS_NOTSUPP; + } + if (unlikely(blkif_req(req)->error)) { +@@ -1638,9 +1638,9 @@ static irqreturn_t blkif_interrupt(int i + /* fall through */ + case BLKIF_OP_READ: + case BLKIF_OP_WRITE: +- if (unlikely(bret->status != BLKIF_RSP_OKAY)) ++ if (unlikely(bret.status != BLKIF_RSP_OKAY)) + dev_dbg(&info->xbdev->dev, "Bad return from blkdev data " +- "request: %x\n", bret->status); ++ "request: %x\n", bret.status); + + break; + default: diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/xsa-155/xsa-155-qsb-023-xen-blkfront-prepare-request-locally-only-then-put-i.patch b/recipes-kernel/linux/files/openxt-kmeta/patches/xsa-155/xsa-155-qsb-023-xen-blkfront-prepare-request-locally-only-then-put-i.patch new file mode 100644 index 0000000000..63d5b5ba50 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/xsa-155/xsa-155-qsb-023-xen-blkfront-prepare-request-locally-only-then-put-i.patch @@ -0,0 +1,136 @@ +################################################################################ +SHORT DESCRIPTION: +################################################################################ +QSB-023 (https://github.com/QubesOS/qubes-secpack/blob/master/QSBs/qsb-023-2015) +XSA-155 additional patches for the Xen network and block frontends from Qubes +OS Project. + +################################################################################ +LONG DESCRIPTION: +################################################################################ +Source: https://github.com/QubesOS/qubes-linux-kernel/tree/stable-3.18/patches.xen +Patch: xsa155-linux318-0013-xen-blkfront-prepare-request-locally-only-then-put-i.patch + +Do not reuse data which theoretically might be already modified by the +backend. This is mostly about private copy of the request +(info->shadow[id].req) - make sure the request saved there is really the +one just filled. + +################################################################################ +PATCHES +################################################################################ +--- a/drivers/block/xen-blkfront.c ++++ b/drivers/block/xen-blkfront.c +@@ -692,7 +692,8 @@ static void blkif_setup_extra_req(struct + static int blkif_queue_rw_req(struct request *req, struct blkfront_ring_info *rinfo) + { + struct blkfront_info *info = rinfo->dev_info; +- struct blkif_request *ring_req, *extra_ring_req = NULL; ++ struct blkif_request ring_req, extra_ring_req; ++ struct blkif_request *__ring_req, *__extra_ring_req = NULL; + unsigned long id, extra_id = NO_ASSOCIATED_ID; + bool require_extra_req = false; + int i; +@@ -737,7 +738,8 @@ static int blkif_queue_rw_req(struct req + } + + /* Fill out a communications ring structure. */ +- id = blkif_ring_get_request(rinfo, req, &ring_req); ++ id = blkif_ring_get_request(rinfo, req, &__ring_req); ++ ring_req = *__ring_req; + + num_sg = blk_rq_map_sg(req->q, req, rinfo->shadow[id].sg); + num_grant = 0; +@@ -757,16 +759,16 @@ static int blkif_queue_rw_req(struct req + * BLKIF_OP_WRITE + */ + BUG_ON(req_op(req) == REQ_OP_FLUSH || req->cmd_flags & REQ_FUA); +- ring_req->operation = BLKIF_OP_INDIRECT; +- ring_req->u.indirect.indirect_op = rq_data_dir(req) ? ++ ring_req.operation = BLKIF_OP_INDIRECT; ++ ring_req.u.indirect.indirect_op = rq_data_dir(req) ? + BLKIF_OP_WRITE : BLKIF_OP_READ; +- ring_req->u.indirect.sector_number = (blkif_sector_t)blk_rq_pos(req); +- ring_req->u.indirect.handle = info->handle; +- ring_req->u.indirect.nr_segments = num_grant; ++ ring_req.u.indirect.sector_number = (blkif_sector_t)blk_rq_pos(req); ++ ring_req.u.indirect.handle = info->handle; ++ ring_req.u.indirect.nr_segments = num_grant; + } else { +- ring_req->u.rw.sector_number = (blkif_sector_t)blk_rq_pos(req); +- ring_req->u.rw.handle = info->handle; +- ring_req->operation = rq_data_dir(req) ? ++ ring_req.u.rw.sector_number = (blkif_sector_t)blk_rq_pos(req); ++ ring_req.u.rw.handle = info->handle; ++ ring_req.operation = rq_data_dir(req) ? + BLKIF_OP_WRITE : BLKIF_OP_READ; + if (req_op(req) == REQ_OP_FLUSH || req->cmd_flags & REQ_FUA) { + /* +@@ -777,25 +779,25 @@ static int blkif_queue_rw_req(struct req + * since it is guaranteed ordered WRT previous writes.) + */ + if (info->feature_flush && info->feature_fua) +- ring_req->operation = ++ ring_req.operation = + BLKIF_OP_WRITE_BARRIER; + else if (info->feature_flush) +- ring_req->operation = ++ ring_req.operation = + BLKIF_OP_FLUSH_DISKCACHE; + else +- ring_req->operation = 0; ++ ring_req.operation = 0; + } +- ring_req->u.rw.nr_segments = num_grant; ++ ring_req.u.rw.nr_segments = num_grant; + if (unlikely(require_extra_req)) { +- extra_id = blkif_ring_get_request(rinfo, req, +- &extra_ring_req); ++ extra_id = blkif_ring_get_request(rinfo, req, &__extra_ring_req); ++ extra_ring_req = *__extra_ring_req; + /* + * Only the first request contains the scatter-gather + * list. + */ + rinfo->shadow[extra_id].num_sg = 0; + +- blkif_setup_extra_req(ring_req, extra_ring_req); ++ blkif_setup_extra_req(&ring_req, &extra_ring_req); + + /* Link the 2 requests together */ + rinfo->shadow[extra_id].associated_id = id; +@@ -803,12 +805,12 @@ static int blkif_queue_rw_req(struct req + } + } + +- setup.ring_req = ring_req; ++ setup.ring_req = &ring_req; + setup.id = id; + + setup.require_extra_req = require_extra_req; + if (unlikely(require_extra_req)) +- setup.extra_ring_req = extra_ring_req; ++ setup.extra_ring_req = &extra_ring_req; + + for_each_sg(rinfo->shadow[id].sg, sg, num_sg, i) { + BUG_ON(sg->offset + sg->length > PAGE_SIZE); +@@ -830,10 +832,16 @@ static int blkif_queue_rw_req(struct req + if (setup.segments) + kunmap_atomic(setup.segments); + ++ /* make the request available to the backend */ ++ *__ring_req = ring_req; ++ + /* Keep a private copy so we can reissue requests when recovering. */ +- rinfo->shadow[id].req = *ring_req; +- if (unlikely(require_extra_req)) +- rinfo->shadow[extra_id].req = *extra_ring_req; ++ rinfo->shadow[id].req = ring_req; ++ ++ if (unlikely(require_extra_req)) { ++ rinfo->shadow[extra_id].req = extra_ring_req; ++ *__extra_ring_req = extra_ring_req; ++ } + + if (new_persistent_gnts) + gnttab_free_grant_references(setup.gref_head); diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/xsa-155/xsa-155-qsb-023-xen-netfront-add-range-check-for-Tx-response-id.patch b/recipes-kernel/linux/files/openxt-kmeta/patches/xsa-155/xsa-155-qsb-023-xen-netfront-add-range-check-for-Tx-response-id.patch new file mode 100644 index 0000000000..b43c937bb2 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/xsa-155/xsa-155-qsb-023-xen-netfront-add-range-check-for-Tx-response-id.patch @@ -0,0 +1,29 @@ +################################################################################ +SHORT DESCRIPTION: +################################################################################ +QSB-023 (https://github.com/QubesOS/qubes-secpack/blob/master/QSBs/qsb-023-2015) +XSA-155 additional patches for the Xen network and block frontends from Qubes +OS Project. + +################################################################################ +LONG DESCRIPTION: +################################################################################ +Source: https://github.com/QubesOS/qubes-linux-kernel/tree/stable-3.18/patches.xen +Patch: xsa155-linux-0011-xen-netfront-add-range-check-for-Tx-response-id.patch + +Tx response ID is fetched from shared page, so make sure it is sane +before using it as an array index. + +################################################################################ +PATCHES +################################################################################ +--- a/drivers/net/xen-netfront.c ++++ b/drivers/net/xen-netfront.c +@@ -394,6 +394,7 @@ static void xennet_tx_buf_gc(struct netf + continue; + + id = txrsp->id; ++ BUG_ON(id >= NET_TX_RING_SIZE); + skb = queue->tx_skbs[id].skb; + if (unlikely(gnttab_query_foreign_access( + queue->grant_tx_ref[id]) != 0)) { diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/xsa-155/xsa-155-qsb-023-xen-netfront-copy-response-out-of-shared-buffer-befo.patch b/recipes-kernel/linux/files/openxt-kmeta/patches/xsa-155/xsa-155-qsb-023-xen-netfront-copy-response-out-of-shared-buffer-befo.patch new file mode 100644 index 0000000000..9f04c47cfc --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/xsa-155/xsa-155-qsb-023-xen-netfront-copy-response-out-of-shared-buffer-befo.patch @@ -0,0 +1,174 @@ +################################################################################ +SHORT DESCRIPTION: +################################################################################ +QSB-023 (https://github.com/QubesOS/qubes-secpack/blob/master/QSBs/qsb-023-2015) +XSA-155 additional patches for the Xen network and block frontends from Qubes +OS Project. + +################################################################################ +LONG DESCRIPTION: +################################################################################ +Source: https://github.com/QubesOS/qubes-linux-kernel/tree/stable-3.18/patches.xen +Patch: xsa155-linux318-0009-xen-netfront-copy-response-out-of-shared-buffer-befo.patch + +Make local copy of the response, otherwise backend might modify it while +frontend is already processing it - leading to time of check / time of +use issue. + +################################################################################ +PATCHES +################################################################################ +--- a/drivers/net/xen-netfront.c ++++ b/drivers/net/xen-netfront.c +@@ -387,13 +387,13 @@ static void xennet_tx_buf_gc(struct netf + rmb(); /* Ensure we see responses up to 'rp'. */ + + for (cons = queue->tx.rsp_cons; cons != prod; cons++) { +- struct xen_netif_tx_response *txrsp; ++ struct xen_netif_tx_response txrsp; + +- txrsp = RING_GET_RESPONSE(&queue->tx, cons); +- if (txrsp->status == XEN_NETIF_RSP_NULL) ++ RING_COPY_RESPONSE(&queue->tx, cons, &txrsp); ++ if (txrsp.status == XEN_NETIF_RSP_NULL) + continue; + +- id = txrsp->id; ++ id = txrsp.id; + BUG_ON(id >= NET_TX_RING_SIZE); + skb = queue->tx_skbs[id].skb; + if (unlikely(gnttab_query_foreign_access( +@@ -742,7 +742,7 @@ static int xennet_get_extras(struct netf + RING_IDX rp) + + { +- struct xen_netif_extra_info *extra; ++ struct xen_netif_extra_info extra; + struct device *dev = &queue->info->netdev->dev; + RING_IDX cons = queue->rx.rsp_cons; + int err = 0; +@@ -758,24 +758,23 @@ static int xennet_get_extras(struct netf + break; + } + +- extra = (struct xen_netif_extra_info *) +- RING_GET_RESPONSE(&queue->rx, ++cons); ++ RING_COPY_RESPONSE(&queue->rx, ++cons, &extra); + +- if (unlikely(!extra->type || +- extra->type >= XEN_NETIF_EXTRA_TYPE_MAX)) { ++ if (unlikely(!extra.type || ++ extra.type >= XEN_NETIF_EXTRA_TYPE_MAX)) { + if (net_ratelimit()) + dev_warn(dev, "Invalid extra type: %d\n", +- extra->type); ++ extra.type); + err = -EINVAL; + } else { +- memcpy(&extras[extra->type - 1], extra, +- sizeof(*extra)); ++ memcpy(&extras[extra.type - 1], &extra, ++ sizeof(extra)); + } + + skb = xennet_get_rx_skb(queue, cons); + ref = xennet_get_rx_ref(queue, cons); + xennet_move_rx_slot(queue, skb, ref); +- } while (extra->flags & XEN_NETIF_EXTRA_FLAG_MORE); ++ } while (extra.flags & XEN_NETIF_EXTRA_FLAG_MORE); + + queue->rx.rsp_cons = cons; + return err; +@@ -785,28 +784,28 @@ static int xennet_get_responses(struct n + struct netfront_rx_info *rinfo, RING_IDX rp, + struct sk_buff_head *list) + { +- struct xen_netif_rx_response *rx = &rinfo->rx; ++ struct xen_netif_rx_response rx = rinfo->rx; + struct xen_netif_extra_info *extras = rinfo->extras; + struct device *dev = &queue->info->netdev->dev; + RING_IDX cons = queue->rx.rsp_cons; + struct sk_buff *skb = xennet_get_rx_skb(queue, cons); + grant_ref_t ref = xennet_get_rx_ref(queue, cons); +- int max = XEN_NETIF_NR_SLOTS_MIN + (rx->status <= RX_COPY_THRESHOLD); ++ int max = XEN_NETIF_NR_SLOTS_MIN + (rx.status <= RX_COPY_THRESHOLD); + int slots = 1; + int err = 0; + unsigned long ret; + +- if (rx->flags & XEN_NETRXF_extra_info) { ++ if (rx.flags & XEN_NETRXF_extra_info) { + err = xennet_get_extras(queue, extras, rp); + cons = queue->rx.rsp_cons; + } + + for (;;) { +- if (unlikely(rx->status < 0 || +- rx->offset + rx->status > XEN_PAGE_SIZE)) { ++ if (unlikely(rx.status < 0 || ++ rx.offset + rx.status > XEN_PAGE_SIZE)) { + if (net_ratelimit()) +- dev_warn(dev, "rx->offset: %u, size: %d\n", +- rx->offset, rx->status); ++ dev_warn(dev, "rx.offset: %u, size: %d\n", ++ rx.offset, rx.status); + xennet_move_rx_slot(queue, skb, ref); + err = -EINVAL; + goto next; +@@ -820,7 +819,7 @@ static int xennet_get_responses(struct n + if (ref == GRANT_INVALID_REF) { + if (net_ratelimit()) + dev_warn(dev, "Bad rx response id %d.\n", +- rx->id); ++ rx.id); + err = -EINVAL; + goto next; + } +@@ -833,7 +832,7 @@ static int xennet_get_responses(struct n + __skb_queue_tail(list, skb); + + next: +- if (!(rx->flags & XEN_NETRXF_more_data)) ++ if (!(rx.flags & XEN_NETRXF_more_data)) + break; + + if (cons + slots == rp) { +@@ -843,7 +842,7 @@ next: + break; + } + +- rx = RING_GET_RESPONSE(&queue->rx, cons + slots); ++ RING_COPY_RESPONSE(&queue->rx, cons + slots, &rx); + skb = xennet_get_rx_skb(queue, cons + slots); + ref = xennet_get_rx_ref(queue, cons + slots); + slots++; +@@ -898,9 +897,9 @@ static int xennet_fill_frags(struct netf + struct sk_buff *nskb; + + while ((nskb = __skb_dequeue(list))) { +- struct xen_netif_rx_response *rx = +- RING_GET_RESPONSE(&queue->rx, ++cons); ++ struct xen_netif_rx_response rx; + skb_frag_t *nfrag = &skb_shinfo(nskb)->frags[0]; ++ RING_COPY_RESPONSE(&queue->rx, ++cons, &rx); + + if (skb_shinfo(skb)->nr_frags == MAX_SKB_FRAGS) { + unsigned int pull_to = NETFRONT_SKB_CB(skb)->pull_to; +@@ -916,7 +915,7 @@ static int xennet_fill_frags(struct netf + + skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, + skb_frag_page(nfrag), +- rx->offset, rx->status, PAGE_SIZE); ++ rx.offset, rx.status, PAGE_SIZE); + + skb_shinfo(nskb)->nr_frags = 0; + kfree_skb(nskb); +@@ -1014,7 +1013,7 @@ static int xennet_poll(struct napi_struc + i = queue->rx.rsp_cons; + work_done = 0; + while ((i != rp) && (work_done < budget)) { +- memcpy(rx, RING_GET_RESPONSE(&queue->rx, i), sizeof(*rx)); ++ RING_COPY_RESPONSE(&queue->rx, i, rx); + memset(extras, 0, sizeof(rinfo.extras)); + + err = xennet_get_responses(queue, &rinfo, rp, &tmpq); diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/xsa-155/xsa-155-qsb-023-xen-netfront-do-not-use-data-already-exposed-to-back.patch b/recipes-kernel/linux/files/openxt-kmeta/patches/xsa-155/xsa-155-qsb-023-xen-netfront-do-not-use-data-already-exposed-to-back.patch new file mode 100644 index 0000000000..c69bdfffb3 --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/xsa-155/xsa-155-qsb-023-xen-netfront-do-not-use-data-already-exposed-to-back.patch @@ -0,0 +1,59 @@ +################################################################################ +SHORT DESCRIPTION: +################################################################################ +QSB-023 (https://github.com/QubesOS/qubes-secpack/blob/master/QSBs/qsb-023-2015) +XSA-155 additional patches for the Xen network and block frontends from Qubes +OS Project. + +################################################################################ +LONG DESCRIPTION: +################################################################################ +Source: https://github.com/QubesOS/qubes-linux-kernel/tree/stable-3.18/patches.xen +Patch: xsa155-linux318-0010-xen-netfront-do-not-use-data-already-exposed-to-back.patch + +Backend may freely modify anything on shared page, so use data which was +supposed to be written there, instead of reading it back from the shared pckend +may freely modify anything on shared page, so use data which was supposed to be +written there, instead of reading it back from the shared page. + +################################################################################ +PATCHES +################################################################################ +--- a/drivers/net/xen-netfront.c ++++ b/drivers/net/xen-netfront.c +@@ -459,7 +459,7 @@ static void xennet_tx_setup_grant(unsign + tx->flags = 0; + + info->tx = tx; +- info->size += tx->size; ++ info->size += len; + } + + static struct xen_netif_tx_request *xennet_make_first_txreq( +@@ -575,7 +575,7 @@ static netdev_tx_t xennet_start_xmit(str + int slots; + struct page *page; + unsigned int offset; +- unsigned int len; ++ unsigned int len, this_len; + unsigned long flags; + struct netfront_queue *queue = NULL; + unsigned int num_queues = dev->real_num_tx_queues; +@@ -635,14 +635,15 @@ static netdev_tx_t xennet_start_xmit(str + } + + /* First request for the linear area. */ ++ this_len = min_t(unsigned int, PAGE_SIZE - offset, len); + first_tx = tx = xennet_make_first_txreq(queue, skb, + page, offset, len); +- offset += tx->size; ++ offset += this_len; + if (offset == PAGE_SIZE) { + page++; + offset = 0; + } +- len -= tx->size; ++ len -= this_len; + + if (skb->ip_summed == CHECKSUM_PARTIAL) + /* local packet? */ diff --git a/recipes-kernel/linux/files/openxt-kmeta/patches/xsa-155/xsa-155.scc b/recipes-kernel/linux/files/openxt-kmeta/patches/xsa-155/xsa-155.scc new file mode 100644 index 0000000000..901695c60e --- /dev/null +++ b/recipes-kernel/linux/files/openxt-kmeta/patches/xsa-155/xsa-155.scc @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: MIT +define KFEATURE_DESCRIPTION "Apply XSA-155 mitigation patches for service VM" +define KFEATURE_COMPATIBILITY all + +patch xsa-155-qsb-023-add-RING_COPY_RESPONSE.patch +patch xsa-155-qsb-023-xen-blkfront-make-local-copy-of-response-before-usin.patch +patch xsa-155-qsb-023-xen-blkfront-prepare-request-locally-only-then-put-i.patch +patch xsa-155-qsb-023-xen-netfront-add-range-check-for-Tx-response-id.patch +patch xsa-155-qsb-023-xen-netfront-copy-response-out-of-shared-buffer-befo.patch +patch xsa-155-qsb-023-xen-netfront-do-not-use-data-already-exposed-to-back.patch diff --git a/recipes-kernel/linux/linux-yocto-openxt-5.4.inc b/recipes-kernel/linux/linux-yocto-openxt-5.4.inc new file mode 100644 index 0000000000..cb5f3e9a39 --- /dev/null +++ b/recipes-kernel/linux/linux-yocto-openxt-5.4.inc @@ -0,0 +1,30 @@ +KBRANCH ?= "v5.4/standard/base" + +require recipes-kernel/linux/linux-yocto.inc + +SRC_URI = " \ + git://git.yoctoproject.org/linux-yocto.git;name=machine;branch=${KBRANCH}; \ + git://git.yoctoproject.org/yocto-kernel-cache;type=kmeta;name=meta;branch=yocto-5.4;destsuffix=${KMETA} \ +" +SRC_URI_append += " \ + file://openxt-kmeta;type=kmeta;destsuffix=openxt-kmeta \ +" + +SRCREV_machine = "v5.4.106" +SRCREV_meta = "6144556fdee152870d8e792d41948ddcf9a684f1" + +LIC_FILES_CHKSUM = "file://COPYING;md5=bbea815ee2795b2f4230826c0c6b8814" +LINUX_VERSION ?= "5.4.106" + +inherit kernel-module-signing + +DEPENDS += " \ + ${@bb.utils.contains('ARCH', 'x86', 'elfutils-native', '', d)} \ + openssl-native \ + util-linux-native \ +" + +PV = "${LINUX_VERSION}+git${SRCPV}" + +KMETA = "kernel-data" +KCONF_BSP_AUDIT_LEVEL = "2" diff --git a/recipes-kernel/linux/linux-yocto-openxt-dom0_5.4.bb b/recipes-kernel/linux/linux-yocto-openxt-dom0_5.4.bb new file mode 100644 index 0000000000..e62e5fd648 --- /dev/null +++ b/recipes-kernel/linux/linux-yocto-openxt-dom0_5.4.bb @@ -0,0 +1,68 @@ +COMPATIBLE_MACHINE = "openxt-dom0" + +KMACHINE = "intel-x86-64" +LINUX_KERNEL_TYPE = "dom0" + +KERNEL_FEATURES += " \ + \ + features/rfkill/rfkill.scc \ + \ + features/mmc/mmc-sdhci.scc \ + \ + features/scsi/disk.scc \ + features/scsi/cdrom.scc \ + \ + features/input/input.scc \ + \ + cfg/vesafb.scc \ + cfg/usb-mass-storage.scc \ + cfg/efi-ext.scc \ + \ + features/power/intel.scc \ + \ + features/i915/i915.scc \ + features/drm-gma500/drm-gma500.scc \ + features/sound/snd_hda_intel.scc \ + \ + features/tpm/tpm.scc \ + \ + features/xen/xen-net-fe.scc \ + features/xen/xen-balloon.scc \ + features/xen/xen-blk-be.scc \ + features/xen/xen-pci-be.scc \ + \ + cgl/features/selinux/selinux.scc \ + \ + bsp/laptop/laptop-dell.scc \ + bsp/laptop/laptop-hp.scc \ + bsp/laptop/laptop-thinkpad.scc \ + \ + bsp/common-pc/common-pc-hid.scc \ + \ + bsp/gpu/nouveau.scc \ + bsp/gpu/radeon.scc \ + \ + features/usb/touchscreen-composite.scc \ + features/usb/ehci-hcd.scc \ + features/usb/uhci-hcd.scc \ + features/usb/ohci-hcd.scc \ + features/usb/xhci-hcd.scc \ + \ + cfg/openxt-common.scc \ + cfg/luks-lvm.cfg \ + cfg/initrd-gz.scc \ + \ + patches/backports/backports.scc \ + patches/blktap2/blktap2.scc \ + patches/openxt-input-quirks/openxt-input-quirks.scc \ + patches/openxt-pci-quirks/openxt-pci-quirks.scc \ + patches/openxt-serial-quirks/openxt-serial-quirks.scc \ + patches/openxt-service-vms/openxt-service-vms.scc \ + patches/openxt-tpm/openxt-tpm.scc \ + patches/openxt-usbback/openxt-usbback.scc \ + patches/openxt-video-quirks/openxt-video-quirks.scc \ + patches/xen-txt/xen-txt.scc \ + patches/xsa-155/xsa-155.scc \ +" + +require linux-yocto-openxt-5.4.inc diff --git a/recipes-kernel/linux/linux-yocto-openxt-installer_5.4.bb b/recipes-kernel/linux/linux-yocto-openxt-installer_5.4.bb new file mode 100644 index 0000000000..c1a478d22e --- /dev/null +++ b/recipes-kernel/linux/linux-yocto-openxt-installer_5.4.bb @@ -0,0 +1,47 @@ +COMPATIBLE_MACHINE = "openxt-live-installer" + +KMACHINE = "intel-x86-64" +LINUX_KERNEL_TYPE = "livecd-xen" + +KERNEL_FEATURES += " \ + cfg/vesafb.scc \ + cfg/usb-mass-storage.scc \ + cfg/efi-ext.scc \ + \ + features/power/intel.scc \ + \ + features/i915/i915.scc \ + features/drm-gma500/drm-gma500.scc \ + features/sound/snd_hda_intel.scc \ + \ + features/tpm/tpm.scc \ + \ + bsp/laptop/laptop-dell.scc \ + bsp/laptop/laptop-hp.scc \ + bsp/laptop/laptop-thinkpad.scc \ + \ + bsp/common-pc/common-pc-hid.scc \ + features/usb/touchscreen-composite.scc \ + \ + bsp/gpu/nouveau.scc \ + bsp/gpu/radeon.scc \ + \ + features/usb/ehci-hcd.scc \ + features/usb/uhci-hcd.scc \ + features/usb/ohci-hcd.scc \ + features/usb/xhci-hcd.scc \ + \ + bsp/common-pc/common-pc-eth-extended.scc \ + bsp/common-pc/common-pc-wifi-extended.scc \ + \ + cfg/openxt-common.scc \ + cfg/luks-lvm.cfg \ + cfg/initrd-gz.scc \ + cfg/livecd-fs.scc \ + \ + patches/backports/backports.scc \ + patches/openxt-input-quirks/openxt-input-quirks.scc \ + patches/openxt-tpm/openxt-tpm.scc \ +" + +require linux-yocto-openxt-5.4.inc diff --git a/recipes-kernel/linux/linux-yocto-openxt-ndvm_5.4.bb b/recipes-kernel/linux/linux-yocto-openxt-ndvm_5.4.bb new file mode 100644 index 0000000000..dada160d67 --- /dev/null +++ b/recipes-kernel/linux/linux-yocto-openxt-ndvm_5.4.bb @@ -0,0 +1,23 @@ +COMPATIBLE_MACHINE = "openxt-ndvm" + +KMACHINE = "intel-x86-64" +LINUX_KERNEL_TYPE = "ndvm" + +KERNEL_FEATURES += " \ + cgl/features/selinux/selinux.scc \ + features/netfilter/netfilter.scc \ + features/netfilter/netfilter-physdev.scc \ + \ + cfg/openxt-common.scc \ + \ + bsp/common-pc/common-pc-eth-extended.scc \ + bsp/common-pc/common-pc-wifi-extended.scc \ + \ + patches/backports/backports.scc \ + patches/openxt-service-vms/openxt-service-vms.scc \ + patches/openxt-bridge-quirks/openxt-bridge-quirks.scc \ + patches/openxt-vwif/openxt-vwif.scc \ + patches/xsa-155/xsa-155.scc \ +" + +require linux-yocto-openxt-5.4.inc diff --git a/recipes-kernel/linux/linux-yocto-openxt-stubdom_5.4.bb b/recipes-kernel/linux/linux-yocto-openxt-stubdom_5.4.bb new file mode 100644 index 0000000000..efa92a131c --- /dev/null +++ b/recipes-kernel/linux/linux-yocto-openxt-stubdom_5.4.bb @@ -0,0 +1,19 @@ +COMPATIBLE_MACHINE = "openxt-stubdom" + +KMACHINE = "intel-x86-64" +LINUX_KERNEL_TYPE = "stubdom" + +KERNEL_FEATURES += " \ + features/xen/xen-blk-fe.scc \ + features/xen/xen-net-fe.scc \ + features/xen/xen-pci-fe.scc \ + \ + cfg/openxt-common.scc \ + cfg/initrd-gz.scc \ + \ + patches/backports/backports.scc \ + patches/openxt-service-vms/openxt-service-vms.scc \ + patches/xsa-155/xsa-155.scc \ +" + +require linux-yocto-openxt-5.4.inc diff --git a/recipes-kernel/linux/linux-yocto-openxt-uivm_5.4.bb b/recipes-kernel/linux/linux-yocto-openxt-uivm_5.4.bb new file mode 100644 index 0000000000..46dc1083b6 --- /dev/null +++ b/recipes-kernel/linux/linux-yocto-openxt-uivm_5.4.bb @@ -0,0 +1,20 @@ +COMPATIBLE_MACHINE = "openxt-uivm" + +KMACHINE = "intel-x86-64" +LINUX_KERNEL_TYPE = "uivm" + +KERNEL_FEATURES += " \ + features/xen/xen-blk-fe.scc \ + features/xen/xen-net-fe.scc \ + features/xen/xen-vkbd-fe.scc \ + features/xen/xen-vfb-fe.scc \ + \ + cfg/openxt-common.scc \ + \ + patches/backports/backports.scc \ + patches/openxt-pv-video-quirks/openxt-pv-video-quirks.scc \ + patches/openxt-service-vms/openxt-service-vms.scc \ + patches/xsa-155/xsa-155.scc \ +" + +require linux-yocto-openxt-5.4.inc diff --git a/recipes-openxt/stubdomains/devicemodel-stubdom_1.0.bb b/recipes-openxt/stubdomains/devicemodel-stubdom_1.0.bb index 2d3ea4fcb1..7a8f76fccc 100644 --- a/recipes-openxt/stubdomains/devicemodel-stubdom_1.0.bb +++ b/recipes-openxt/stubdomains/devicemodel-stubdom_1.0.bb @@ -4,7 +4,7 @@ LICENSE = "GPLv2" LIC_FILES_CHKSUM ?= "file://${COMMON_LICENSE_DIR}/GPL-2.0;md5=801f80980d171dd6425610833a22dbe6" STUBDOMAIN_DIR = "${DEPLOY_DIR}/images/${STUBDOMAIN_MACHINE}" -STUBDOMAIN_NAME = "xenclient-stubdomain-initramfs-image" +STUBDOMAIN_NAME = "openxt-stubdom-initramfs-image" FILESEXTRAPATHS_prepend := "${STUBDOMAIN_DIR}:" diff --git a/recipes-openxt/stubdomains/openxt-stubdom-kernel_1.0.bb b/recipes-openxt/stubdomains/openxt-stubdom-kernel_1.0.bb new file mode 100644 index 0000000000..1d1c858285 --- /dev/null +++ b/recipes-openxt/stubdomains/openxt-stubdom-kernel_1.0.bb @@ -0,0 +1,28 @@ +SUMMARY = "Recipe for packaging stubdomain kernel" +HOMEPAGE = "https://openxt.org" +LICENSE = "GPLv2" +LIC_FILES_CHKSUM ?= "file://${COMMON_LICENSE_DIR}/GPL-2.0;md5=801f80980d171dd6425610833a22dbe6" + +STUBDOMAIN_DIR = "${DEPLOY_DIR}/images/${STUBDOMAIN_MACHINE}" + +FILESEXTRAPATHS_prepend := "${STUBDOMAIN_DIR}:" + +SRC_URI = " \ + file://${STUBDOMAIN_KERNEL}-${STUBDOMAIN_MACHINE}.bin \ +" + +do_install() { + install -d ${D}${libdir}/xen/boot + install -m 0644 ${WORKDIR}/${STUBDOMAIN_KERNEL}-${STUBDOMAIN_MACHINE}.bin \ + ${D}${libdir}/xen/boot/stubdomain-bzImage +} + +do_checkimage() { + if [ ! -e "${STUBDOMAIN_DIR}/${STUBDOMAIN_KERNEL}-${STUBDOMAIN_MACHINE}.bin" ]; then + bbfatal "The stubdomain kernel must be built first" + fi +} +addtask checkimage before do_fetch + +FILES_${PN} = "${libdir}/xen/boot/stubdomain-bzImage" + diff --git a/recipes-openxt/txt-info-module/files/sources/Kbuild b/recipes-openxt/txt-info-module/files/sources/Kbuild deleted file mode 100644 index 0aaa2a8a5a..0000000000 --- a/recipes-openxt/txt-info-module/files/sources/Kbuild +++ /dev/null @@ -1,3 +0,0 @@ -obj-m += txt_info.o - -ccflags-y := -I$(src)/include diff --git a/recipes-openxt/txt-info-module/files/sources/Makefile b/recipes-openxt/txt-info-module/files/sources/Makefile deleted file mode 100644 index 4a9cce3b0d..0000000000 --- a/recipes-openxt/txt-info-module/files/sources/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -ifneq ($(KERNELRELEASE),) -# kbuild part of makefile -include Kbuild - -else -# normal makefile -KERNEL_VERSION ?= `uname -r` -KERNEL_SRC ?= /lib/modules/$(KERNEL_VERSION)/build -INSTALL_HDR_PATH ?= /usr - -default: - $(MAKE) -C $(KERNEL_SRC) M=$$PWD - -clean: - $(MAKE) -C $(KERNEL_SRC) M=$$PWD clean - -modules_install: - $(MAKE) -C $(KERNEL_SRC) M=$$PWD modules_install - -endif diff --git a/recipes-openxt/txt-info-module/files/sources/txt_info.c b/recipes-openxt/txt-info-module/files/sources/txt_info.c deleted file mode 100644 index ebece6a506..0000000000 --- a/recipes-openxt/txt-info-module/files/sources/txt_info.c +++ /dev/null @@ -1,167 +0,0 @@ -#include -#include -#include -#include -#include - -#define TXT_PUB_CR_BASE 0xfed30000 -#define TXT_PUB_CR_SIZE 0x10000 -static const struct resource txt_resources[] = { - { - .start = TXT_PUB_CR_BASE, - .end = TXT_PUB_CR_BASE + TXT_PUB_CR_SIZE - 1, - .flags = IORESOURCE_MEM, - }, -}; -#define TXT_PUB_CR_INDEX 0 - -struct platform_device *pdev; -struct txt_info { - void __iomem *cr_pub; - void __iomem *cr_priv; -}; -static struct txt_info txt_info; - -static void __iomem *txt_info_map_regs(struct platform_device *pdev, - size_t index) -{ - struct resource *res; - void __iomem *base; - - res = platform_get_resource(pdev, IORESOURCE_MEM, index); - if (IS_ERR(res)) { - dev_dbg(&pdev->dev, - "Failed to access IOMEM resource %zu.\n", index); - return res; - } - - base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); - if (IS_ERR(base)) - dev_dbg(&pdev->dev, - "Failed to ioremap configuration registers.\n"); - - return base; -} - -/* Registers offset from TXT_PUB_CR_BASE */ -#define TXT_STS_OFFSET 0x000 -#define TXT_ESTS_OFFSET 0x008 -#define TXT_ERRORCODE_OFFSET 0x030 -#define TXT_VER_FSBIF_OFFSET 0x100 -#define TXT_DIDVID_OFFSET 0x110 -#define TXT_VER_QPIIF_OFFSET 0x200 - -#define DECLARE_PUB_SHOW_U8(name, offset) \ -static ssize_t name##_show(struct kobject *kobj, \ - struct kobj_attribute *attr, char *buf) \ -{ \ - uint8_t v = ioread8(txt_info.cr_pub + (offset)); \ - return sprintf(buf, "%#04x\n", v); \ -} \ -static struct kobj_attribute txt_attr_##name = __ATTR_RO(name); - -#define DECLARE_PUB_SHOW_U32(name, offset) \ -static ssize_t name##_show(struct kobject *kobj, \ - struct kobj_attribute *attr, char *buf) \ -{ \ - uint32_t v = ioread32(txt_info.cr_pub + (offset)); \ - return sprintf(buf, "%#010x\n", v); \ -} \ -static struct kobj_attribute txt_attr_##name = __ATTR_RO(name); - -#define DECLARE_PUB_SHOW_U64(name, offset) \ -static ssize_t name##_show(struct kobject *kobj, \ - struct kobj_attribute *attr, char *buf) \ -{ \ - uint64_t v = ioread32(txt_info.cr_pub + (offset) + 0x4); \ - v <<= 32; \ - v |= ioread32(txt_info.cr_pub + (offset)); \ - return sprintf(buf, "%#018llx\n", v); \ -} \ -static struct kobj_attribute txt_attr_##name = __ATTR_RO(name); - -DECLARE_PUB_SHOW_U64(sts, TXT_STS_OFFSET); -DECLARE_PUB_SHOW_U8(ests, TXT_ESTS_OFFSET); -DECLARE_PUB_SHOW_U32(errorcode, TXT_ERRORCODE_OFFSET); -DECLARE_PUB_SHOW_U32(ver_fsbif, TXT_VER_FSBIF_OFFSET); -DECLARE_PUB_SHOW_U64(didvid, TXT_DIDVID_OFFSET); -DECLARE_PUB_SHOW_U32(ver_qpiif, TXT_VER_QPIIF_OFFSET); - -static struct attribute *txt_subsys_attrs[] = { - &txt_attr_sts.attr, - &txt_attr_ests.attr, - &txt_attr_errorcode.attr, - &txt_attr_ver_fsbif.attr, - &txt_attr_didvid.attr, - &txt_attr_ver_qpiif.attr, - NULL, -}; - -static umode_t txt_attr_is_visible(struct kobject *kobj, - struct attribute *attr, int n) -{ - return attr->mode; -} - -static const struct attribute_group txt_subsys_attr_group = { - .attrs = txt_subsys_attrs, - .is_visible = txt_attr_is_visible, -}; - -struct kobject *txt_kobj; - -static int __init init_txt_info(void) -{ - int rc; - void __iomem *base; - - pr_info("%s\n", __func__); - - pdev = platform_device_register_simple( - "txt", -1, txt_resources, ARRAY_SIZE(txt_resources)); - if (IS_ERR(pdev)) { - rc = PTR_ERR(pdev); - pr_err("Failed to register txt platform device driver (%d).\n", rc); - goto fail_register; - } - - base = txt_info_map_regs(pdev, TXT_PUB_CR_INDEX); - if (IS_ERR(base)) { - rc = PTR_ERR(base); - dev_err(&pdev->dev, - "Failed to map TXT public resources (%d).\n", rc); - goto fail_map_pub; - } - txt_info.cr_pub = base; - - rc = sysfs_create_group(&pdev->dev.kobj, &txt_subsys_attr_group); - if (rc) { - dev_err(&pdev->dev, "Failed to create sysfs group (%d).\n", rc); - goto fail_sysfs; - } - - return 0; - -fail_sysfs: - devm_iounmap(&pdev->dev, txt_info.cr_pub); -fail_map_pub: - platform_device_unregister(pdev); -fail_register: - return rc; -} - -static void __exit cleanup_txt_info(void) -{ - pr_info("%s\n", __func__); - - if (pdev) - platform_device_unregister(pdev); -} - -module_init(init_txt_info); -module_exit(cleanup_txt_info); - -MODULE_AUTHOR("Assured Information Security, Inc"); -MODULE_DESCRIPTION("TXT driver."); -MODULE_VERSION("1.0"); -MODULE_LICENSE("GPL"); diff --git a/recipes-openxt/txt-info-module/txt-info-module_1.0.bb b/recipes-openxt/txt-info-module/txt-info-module_1.0.bb deleted file mode 100644 index a1131ba0d0..0000000000 --- a/recipes-openxt/txt-info-module/txt-info-module_1.0.bb +++ /dev/null @@ -1,24 +0,0 @@ -SUMMARY = "Out-of-tree module to expose TXT resources to user-land." -DESCRIPTION = "TXT exposes configuration registers documented in its Software \ -Development Guide. Accessing these registers in sometimes necessary for \ -userland software to perform checks and validate compatibility with software \ -resources." -LICENSE = "GPLv2" -LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/GPL-2.0;md5=801f80980d171dd6425610833a22dbe6" - -SRC_URI = " \ - file://sources/Kbuild \ - file://sources/Makefile \ - file://sources/txt_info.c \ -" - -S = "${WORKDIR}/sources" - -inherit module -inherit module-signing - -KERNEL_MODULE_AUTOLOAD += "txt_info" - -RDEPENDS_${PN} += " \ - kernel-module-txt \ -" diff --git a/recipes-openxt/xenclient-dom0-tweaks/xenclient-dom0-tweaks/grub.cfg b/recipes-openxt/xenclient-dom0-tweaks/xenclient-dom0-tweaks/grub.cfg index 935d7cd66e..95516ef53b 100644 --- a/recipes-openxt/xenclient-dom0-tweaks/xenclient-dom0-tweaks/grub.cfg +++ b/recipes-openxt/xenclient-dom0-tweaks/xenclient-dom0-tweaks/grub.cfg @@ -31,7 +31,7 @@ fi TBOOT_COMMON_CMD="min_ram=0x2000000 loglvl=all serial=115200,8n1,0x3f8 logging=serial,memory" XEN_COMMON_CMD="dom0_mem=min:768M,max:768M,768M mbi-video vga=current flask=enforcing loglvl=debug guest_loglvl=debug ucode=-2 smt=0 bootscrub=1 argo=yes,mac-permissive=1" -LINUX_COMMON_CMD="console=hvc0 root=/dev/mapper/xenclient-root ro boot=/dev/mapper/xenclient-boot swiotlb=16384 xen_pciback.passthrough=1 consoleblank=0 video.delay_init=1 vt.global_cursor_default=0 rootfstype=ext3 bootfstype=ext3" +LINUX_COMMON_CMD="console=hvc0 root=/dev/mapper/xenclient-root ro boot=/dev/mapper/xenclient-boot swiotlb=16384 xen_pciback.passthrough=1 consoleblank=0 video.delay_init=1 vt.global_cursor_default=0 rootfstype=ext3 bootfstype=ext3 i915.enable_psr=0" menuentry "XenClient: Normal" { background_image /grub/booting.png diff --git a/recipes-openxt/xenclient-dom0-tweaks/xenclient-dom0-tweaks/openxt.cfg b/recipes-openxt/xenclient-dom0-tweaks/xenclient-dom0-tweaks/openxt.cfg index a726c97308..9c1f3f2dc0 100644 --- a/recipes-openxt/xenclient-dom0-tweaks/xenclient-dom0-tweaks/openxt.cfg +++ b/recipes-openxt/xenclient-dom0-tweaks/xenclient-dom0-tweaks/openxt.cfg @@ -6,30 +6,30 @@ ucode=microcode_intel.bin [openxt-normal] options=placeholder console=com1 dom0_mem=min:768M,max:768M,768M efi=rs,attr=uc com1=115200,8n1,pci mbi-video vga=current flask=enforcing loglvl=debug guest_loglvl=debug smt=0 ucode=-1 bootscrub=1 argo=yes,mac-permissive=1 -kernel=bzImage root=/dev/mapper/xenclient-root ro boot=/dev/mapper/xenclient-boot swiotlb=16384 xen_pciback.passthrough=1 consoleblank=0 video.delay_init=1 vt.global_cursor_default=0 rootfstype=ext3 bootfstype=ext3 console=hvc0 autostart +kernel=bzImage root=/dev/mapper/xenclient-root ro boot=/dev/mapper/xenclient-boot swiotlb=16384 xen_pciback.passthrough=1 consoleblank=0 video.delay_init=1 vt.global_cursor_default=0 rootfstype=ext3 bootfstype=ext3 console=hvc0 i915.enable_psr=0 autostart ramdisk=initrd xsm=policy.24 [openxt-support-safe-graphics] options=console=com1 dom0_mem=min:768M,max:768M,768M efi=rs,attr=uc com1=115200,8n1,pci mbi-video vga=current flask=enforcing loglvl=debug guest_loglvl=debug smt=0 ucode=-1 bootscrub=1 argo=yes,mac-permissive=1 -kernel=bzImage root=/dev/mapper/xenclient-root ro boot=/dev/mapper/xenclient-boot swiotlb=16384 xen_pciback.passthrough=1 consoleblank=0 video.delay_init=1 vt.global_cursor_default=0 rootfstype=ext3 bootfstype=ext3 console=hvc0 safe-graphic nomodeset +kernel=bzImage root=/dev/mapper/xenclient-root ro boot=/dev/mapper/xenclient-boot swiotlb=16384 xen_pciback.passthrough=1 consoleblank=0 video.delay_init=1 vt.global_cursor_default=0 rootfstype=ext3 bootfstype=ext3 console=hvc0 i915.enable_psr=0 safe-graphic nomodeset ramdisk=initrd xsm=policy.24 [openxt-support-amt] options=console=com1,vga dom0_mem=min:768M,max:768M,768M efi=rs,attr=uc com1=115200,8n1,amt mbi-video vga=current flask=enforcing loglvl=debug guest_loglvl=debug smt=0 ucode=-1 bootscrub=1 argo=yes,mac-permissive=1 -kernel=bzImage root=/dev/mapper/xenclient-root ro boot=/dev/mapper/xenclient-boot swiotlb=16384 xen_pciback.passthrough=1 consoleblank=0 video.delay_init=1 vt.global_cursor_default=0 rootfstype=ext3 bootfstype=ext3 console=hvc0 +kernel=bzImage root=/dev/mapper/xenclient-root ro boot=/dev/mapper/xenclient-boot swiotlb=16384 xen_pciback.passthrough=1 consoleblank=0 video.delay_init=1 vt.global_cursor_default=0 rootfstype=ext3 bootfstype=ext3 console=hvc0 i915.enable_psr=0 ramdisk=initrd xsm=policy.24 [openxt-support-console] options=console=com1,vga dom0_mem=min:768M,max:768M,768M efi=rs,attr=uc com1=115200,8n1,pci mbi-video vga=current flask=enforcing loglvl=debug guest_loglvl=debug sync_console smt=0 ucode=-1 bootscrub=1 argo=yes,mac-permissive=1 -kernel=bzImage root=/dev/mapper/xenclient-root ro boot=/dev/mapper/xenclient-boot swiotlb=16384 xen_pciback.passthrough=1 consoleblank=0 video.delay_init=1 vt.global_cursor_default=0 rootfstype=ext3 bootfstype=ext3 console=hvc0 console=tty0 fbcon runlevel=3 +kernel=bzImage root=/dev/mapper/xenclient-root ro boot=/dev/mapper/xenclient-boot swiotlb=16384 xen_pciback.passthrough=1 consoleblank=0 video.delay_init=1 vt.global_cursor_default=0 rootfstype=ext3 bootfstype=ext3 console=hvc0 console=tty0 fbcon runlevel=3 i915.enable_psr=0 ramdisk=initrd xsm=policy.24 [openxt-support-console-amt] options=console=com1,vga dom0_mem=min:768M,max:768M,768M efi=rs,attr=uc com1=115200,8n1,amt mbi-video vga=current flask=enforcing loglvl=debug guest_loglvl=debug sync_console smt=0 ucode=-1 bootscrub=1 argo=yes,mac-permissive=1 -kernel=bzImage root=/dev/mapper/xenclient-root ro boot=/dev/mapper/xenclient-boot swiotlb=16384 xen_pciback.passthrough=1 consoleblank=0 video.delay_init=1 vt.global_cursor_default=0 rootfstype=ext3 bootfstype=ext3 console=hvc0 console=tty0 fbcon runlevel=3 +kernel=bzImage root=/dev/mapper/xenclient-root ro boot=/dev/mapper/xenclient-boot swiotlb=16384 xen_pciback.passthrough=1 consoleblank=0 video.delay_init=1 vt.global_cursor_default=0 rootfstype=ext3 bootfstype=ext3 console=hvc0 console=tty0 fbcon runlevel=3 i915.enable_psr=0 ramdisk=initrd xsm=policy.24 diff --git a/recipes-security/refpolicy/refpolicy-mcs_2.%.bbappend b/recipes-security/refpolicy/refpolicy-mcs_2.%.bbappend index 32f88c4130..199ca037cc 100644 --- a/recipes-security/refpolicy/refpolicy-mcs_2.%.bbappend +++ b/recipes-security/refpolicy/refpolicy-mcs_2.%.bbappend @@ -228,3 +228,8 @@ pkg_postinst_${PN}_append_xenclient-dom0 () { ${base_sbindir}/setfiles "${sysconfdir}/selinux/${POLICY_NAME}/contexts/files/file_contexts" /config /storage fi } +pkg_postinst_${PN}_append_openxt-dom0 () { + if [ -z "$D" ]; then + ${base_sbindir}/setfiles "${sysconfdir}/selinux/${POLICY_NAME}/contexts/files/file_contexts" /config /storage + fi +}