[RFC] Bring in all the Linux headers we depend on in QEMU

Anthony Liguori
2009-05-03T21:37:29Z

[-- Attachment #1: Type: text/plain, Size: 2230 bytes --]

Sorry this explanation is long winded, but this is a messy situation.

In Linux, there isn't a very consistent policy about userspace kernel
header inclusion. On a typical Linux system, you're likely to find
kernel headers in three places.

glibc headers (/usr/include/{linux,asm})

These headers are installed by glibc. They very often are based on much
older kernel versions that the kernel you have in your distribution.
For software that depends on these headers, very often this means that
your software detects features being missing that are present on your
kernel. Furthermore, glibc only installs the headers it needs so very
often certain headers have dependencies that aren't met. A classic
example is linux/compiler.h and the broken usbdevice_fs.h header that
depends on it. There are still distributions today that QEMU doesn't
compile on because of this.

Today, most of QEMU's code depends on these headers.

/lib/modules/$(uname -r)/build

These are the kernel headers that are installed as part of your kernel.
In general, this is a pretty good place to find the headers that are
associated with the kernel version you're actually running on. However,
these headers are part of the kernel build tree and are not always
guaranteed to be includable from userspace.

<random kernel tree>

Developers, in particular, like to point things at their random kernel
trees. In general though, relying on a full kernel source tree being
available isn't a good idea. Kernel headers change dramatically across
versions too so it's very likely that we would need to have a lot of
#ifdefs dependent on kernel versions, or some of the uglier work arounds
we have in usb-linux.c.

I think the best way to avoid #ifdefs and dependencies on
broken/incomplete glibc headers is to include all of the Linux headers
we need within QEMU. The attached patch does just this.

I think there's room for discussion about whether we really want to do
this. We could potentially depend on some more common glibc headers
(like asm/types.h) while bringing in less reliable headers
(if_tun.h/virtio*). Including them all seems like the most robust
solution to me though.

Comments?

Regards,

Anthony Liguori

[-- Attachment #2: 0001-Import-Linux-headers-into-QEMU.patch --]
[-- Type: text/x-patch, Size: 10288 bytes --]

>From b42aa57e94fc6b05897271b0816fa34d70670c9a Mon Sep 17 00:00:00 2001
From: Anthony Liguori <aliguori@us.ibm.com>
Date: Sat, 2 May 2009 15:45:24 -0500
Subject: [PATCH] Import Linux headers into QEMU

These are the headers from Linux 2.6.29 that have been modified to work under
QEMU. This includes the necessary scripts to generate the headers from the
original Linux source tree.

I've not included the headers in this patch as they are quite big and would make
review more difficult. I've included headers for all host architectures QEMU
currently supports but I've only tested x86.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
Makefile.target | 3 --
configure | 37 ++++++++++---------
linux/Makefile | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
linux/README | 19 ++++++++++
linux/fixup.sed | 19 ++++++++++
usb-linux.c | 1 -
6 files changed, 165 insertions(+), 22 deletions(-)
create mode 100644 linux/Makefile
create mode 100644 linux/README
create mode 100644 linux/fixup.sed

diff --git a/Makefile.target b/Makefile.target
index f735105..474245a 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -124,9 +124,6 @@ CFLAGS+=-I/opt/SUNWspro/prod/include/cc
endif
endif

-kvm.o: CFLAGS+=$(KVM_CFLAGS)
-kvm-all.o: CFLAGS+=$(KVM_CFLAGS)
-
all: $(PROGS)

#########################################################
diff --git a/configure b/configure
index 82fb60a..379a2a6 100755
--- a/configure
+++ b/configure
@@ -1081,6 +1081,23 @@ EOF
fi
fi

+# Linux kernel headers CFLAGS
+if test -z "$kerneldir" ; then
+ linux_cflags="-I$source_path/linux"
+else
+ linux_cflags="-I$kerneldir/include"
+ if test \( "$cpu" = "i386" -o "$cpu" = "x86_64" \) \
+ -a -d "$kerneldir/arch/x86/include" ; then
+ linux_cflags="$linux_cflags -I$kerneldir/arch/x86/include"
+ elif test "$cpu" = "ppc" -a -d "$kerneldir/arch/powerpc/include" ; then
+ linux_cflags="$linux_cflags -I$kerneldir/arch/powerpc/include"
+ elif test -d "$kerneldir/arch/$cpu/include" ; then
+ linux_cflags="$linux_cflags -I$kerneldir/arch/$cpu/include"
+ fi
+fi
+
+OS_CFLAGS="$OS_CFLAGS $linux_cflags"
+
##########################################
# kvm probe
if test "$kvm" = "yes" ; then
@@ -1100,27 +1117,14 @@ if test "$kvm" = "yes" ; then
#endif
int main(void) { return 0; }
EOF
- if test "$kerneldir" != "" ; then
- kvm_cflags=-I"$kerneldir"/include
- if test \( "$cpu" = "i386" -o "$cpu" = "x86_64" \) \
- -a -d "$kerneldir/arch/x86/include" ; then
- kvm_cflags="$kvm_cflags -I$kerneldir/arch/x86/include"
- elif test "$cpu" = "ppc" -a -d "$kerneldir/arch/powerpc/include" ; then
- kvm_cflags="$kvm_cflags -I$kerneldir/arch/powerpc/include"
- elif test -d "$kerneldir/arch/$cpu/include" ; then
- kvm_cflags="$kvm_cflags -I$kerneldir/arch/$cpu/include"
- fi
- else
- kvm_cflags=""
- fi
- if $cc $ARCH_CFLAGS -o $TMPE ${OS_CFLAGS} $kvm_cflags $TMPC \
+ if $cc $ARCH_CFLAGS -o $TMPE ${OS_CFLAGS} $TMPC \
> /dev/null 2>/dev/null ; then
:
else
kvm="no";
if [ -x "`which awk 2>/dev/null`" ] && \
[ -x "`which grep 2>/dev/null`" ]; then
- kvmerr=`LANG=C $cc $ARCH_CFLAGS -o $TMPE ${OS_CFLAGS} $kvm_cflags $TMPC 2>&1 \
+ kvmerr=`LANG=C $cc $ARCH_CFLAGS -o $TMPE ${OS_CFLAGS} $TMPC 2>&1 \
| grep "error: " \
| awk -F "error: " '{if (NR>1) printf(", "); printf("%s",$2);}'`
if test "$kvmerr" != "" ; then
@@ -1817,7 +1821,6 @@ case "$target_cpu" in
fi
if test "$kvm" = "yes" ; then
echo "CONFIG_KVM=yes" >> $config_mak
- echo "KVM_CFLAGS=$kvm_cflags" >> $config_mak
echo "#define CONFIG_KVM 1" >> $config_h
fi
if test "$xen" = "yes" -a "$target_softmmu" = "yes";
@@ -1838,7 +1841,6 @@ case "$target_cpu" in
fi
if test "$kvm" = "yes" ; then
echo "CONFIG_KVM=yes" >> $config_mak
- echo "KVM_CFLAGS=$kvm_cflags" >> $config_mak
echo "#define CONFIG_KVM 1" >> $config_h
fi
if test "$xen" = "yes" -a "$target_softmmu" = "yes"
@@ -1906,7 +1908,6 @@ case "$target_cpu" in
echo "#define TARGET_PPCEMB 1" >> $config_h
if test "$kvm" = "yes" ; then
echo "CONFIG_KVM=yes" >> $config_mak
- echo "KVM_CFLAGS=$kvm_cflags" >> $config_mak
echo "#define CONFIG_KVM 1" >> $config_h
fi
gdb_xml_files="power-core.xml power-fpu.xml power-altivec.xml power-spe.xml"
diff --git a/linux/Makefile b/linux/Makefile
new file mode 100644
index 0000000..68a5844
--- /dev/null
+++ b/linux/Makefile
@@ -0,0 +1,108 @@
+KERNELDIR ?= /lib/modules/$(shell uname -r)/build
+
+# Basic types/annotations that Linux headers use
+CORE_HDRS=linux/types.h linux/posix_types.h linux/stddef.h linux/compiler.h
+CORE_HDRS+=linux/byteorder/little_endian.h linux/byteorder/big_endian.h
+CORE_HDRS+=linux/swab.h linux/ioctl.h
+
+CORE_HDRS+=asm-generic/int-ll64.h asm-generic/int-l64.h asm-generic/ioctl.h
+
+CORE_HDRS+=asm-x86/types.h asm-x86/posix_types.h
+CORE_HDRS+=asm-x86/posix_types_32.h asm-x86/posix_types_64.h
+CORE_HDRS+=asm-x86/byteorder.h asm-x86/swab.h asm-x86/ioctl.h
+
+CORE_HDRS+=asm-powerpc/types.h asm-powerpc/posix_types.h
+CORE_HDRS+=asm-powerpc/byteorder.h asm-powerpc/swab.h asm-powerpc/ioctl.h
+
+CORE_HDRS+=asm-sparc/types.h asm-sparc/posix_types.h
+CORE_HDRS+=asm-sparc/byteorder.h asm-sparc/swab.h asm-sparc/ioctl.h
+CORE_HDRS+=asm-sparc/asi.h
+
+CORE_HDRS+=asm-arm/types.h asm-arm/posix_types.h
+CORE_HDRS+=asm-arm/byteorder.h asm-arm/swab.h asm-arm/ioctl.h
+
+CORE_HDRS+=asm-parisc/types.h asm-parisc/posix_types.h
+CORE_HDRS+=asm-parisc/byteorder.h asm-parisc/swab.h asm-parisc/ioctl.h
+
+# Kernel Virtual Machine interface
+KVM_HDRS=linux/kvm.h linux/kvm_para.h
+KVM_HDRS+=asm-x86/kvm.h asm-x86/kvm_para.h
+KVM_HDRS+=asm-powerpc/kvm.h asm-powerpc/kvm_para.h
+
+# VirtIO paravirtual IO framework
+VIRTIO_HDRS=linux/virtio_config.h linux/virtio_net.h linux/virtio_blk.h
+VIRTIO_HDRS+=linux/virtio_console.h linux/virtio_balloon.h
+
+# tun/tap interfaces
+TUN_HDRS=linux/if_tun.h linux/if_ether.h
+
+# timers
+TIMER_HDRS=linux/rtc.h linux/hpet.h
+
+# USB pass through
+USB_HDRS=linux/usbdevice_fs.h linux/magic.h
+
+# IDE/FD
+DISK_HDRS=linux/cdrom.h linux/fd.h
+
+# Parallel port
+PPORT_HDRS=linux/ppdev.h linux/parport.h
+
+sync: sync-kvm sync-virtio sync-tun sync-timer sync-usb sync-disk sync-pport
+
+sync-core: $(CORE_HDRS)
+
+sync-kvm: sync-core $(KVM_HDRS)
+
+sync-virtio: sync-core $(VIRTIO_HDRS)
+
+sync-tun: sync-core $(TUN_HDRS)
+
+sync-timer: sync-core $(TIMER_HDRS)
+
+sync-usb: sync-core $(USB_HDRS)
+
+sync-disk: sync-core $(DISK_HDRS)
+
+sync-pport: sync-core $(PPORT_HDRS)
+
+clean:
+ @$(RM) -r linux asm-x86 asm-powerpc asm-generic asm-sparc asm-arm \
+ asm-parisc
+
+linux/%: $(KERNELDIR)/include/linux/%
+ @mkdir -p $(shell dirname $@)
+ @echo " IMPORT $@"
+ @sed -f fixup.sed $< > $@
+
+asm-generic/%: $(KERNELDIR)/include/asm-generic/%
+ @mkdir -p $(shell dirname $@)
+ @echo " IMPORT $@"
+ @sed -f fixup.sed $< > $@
+
+asm-x86/%: $(KERNELDIR)/arch/x86/include/asm/%
+ @mkdir -p $(shell dirname $@)
+ @echo " IMPORT $@"
+ @sed -f fixup.sed $< > $@
+
+asm-powerpc/%: $(KERNELDIR)/arch/powerpc/include/asm/%
+ @mkdir -p $(shell dirname $@)
+ @echo " IMPORT $@"
+ @sed -f fixup.sed $< > $@
+
+asm-sparc/%: $(KERNELDIR)/arch/sparc/include/asm/%
+ @mkdir -p $(shell dirname $@)
+ @echo " IMPORT $@"
+ @sed -f fixup.sed $< > $@
+
+asm-arm/%: $(KERNELDIR)/arch/arm/include/asm/%
+ @mkdir -p $(shell dirname $@)
+ @echo " IMPORT $@"
+ @sed -f fixup.sed $< > $@
+
+asm-parisc/%: $(KERNELDIR)/arch/parisc/include/asm/%
+ @mkdir -p $(shell dirname $@)
+ @echo " IMPORT $@"
+ @sed -f fixup.sed $< > $@
+
+.PHONY: clean
diff --git a/linux/README b/linux/README
new file mode 100644
index 0000000..e29d39b
--- /dev/null
+++ b/linux/README
@@ -0,0 +1,19 @@
+This directory contains a snapshot of Linux kernel headers. The included
+Makefile was used to import these headers into QEMU.
+
+This process is intended for use by the QEMU maintainers. It is not intended
+to work against arbitrary kernel versions nor is the intention for end-users to
+use this to update the included headers.
+
+If a contributor needs a newer kernel header for a feature implemented
+by a particular patch, please run the appropriate make sync-* command and
+send the results of that command as a separate patch. Also make sure to update
+this file to reflect the kernel version used.
+
+While it is okay for development versions of QEMU to contain headers from
+non-release versions of the Linux kernel, any official release of QEMU must use
+headers from a released version of the Linux kernel to ensure ABI compatibility.
+
+Kernel versions used:
+
+git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git v2.6.30-rc4
diff --git a/linux/fixup.sed b/linux/fixup.sed
new file mode 100644
index 0000000..c0ad124
--- /dev/null
+++ b/linux/fixup.sed
@@ -0,0 +1,19 @@
+# Header file fix ups. This is tailored for importing the kvm linux headers
+
+# Expand asm/ includes to avoid having to do symlink trickery
+s:^#include <asm/\(.*\)>: \
+#if defined(__x86_64__) || defined(__i386__) \
+#include "asm-x86/\1" \
+#elif defined(__powerpc__) \
+#include "asm-powerpc/\1" \
+#elif defined(__sparc__) \
+#include "asm-sparc/\1" \
+#elif defined(__hppa__) \
+#include "asm-parisc/\1" \
+#elif defined(__arm__) \
+#include "asm-arm/\1" \
+#else \
+#error Using Linux headers on unknown architecture \
+#endif \
+:g
+s:^#include <linux/\(.*\)>:#include "linux/\1":g
diff --git a/usb-linux.c b/usb-linux.c
index 70d7a1c..1392579 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -39,7 +39,6 @@
#include <signal.h>

#include <linux/usbdevice_fs.h>
-#include <linux/version.h>
#include "hw/usb.h"

/* We redefine it to avoid version problems */
--
1.6.0.6