Thursday, June 01, 2006

Nvidia driver hack for Xen kernel - SUSE 10.1

I've been wrestling with Xen for a week or so now but before I post some articles about Xen itself I'd like to share this quick hack to get the Nvidia binary driver working with the SUSE 10.1 Xen kernel.

While the 'nv' driver is excellent it's nice to have all the features of my hardware available, even if unfortunately it means using a blob driver from Nvidia. Also the nv driver doesn't seem to probe my monitor using EDID and seems to use more generic modes. This means that while overall image quality is excellent, the DPI is wrong for my hardware and so I have to tweak font sizes and such things. It may be possible to fix this by using custom modelines in my xorg.conf, or to force the nv to probe my screen using EDID but for that amount of effort I may as well get the Nvidia driver working.

Anyway, here's the hack to get the latest Nvidia driver ( 8762 as I write this ) working with the Xen kernel. It should work for x86_64 also but I only tested it for x86. Props to JaXXon on the nvnews.net forums for the original FC patch.


Instructions
Run this shell script as root from the same location as the Nvidia driver package.

#!/bin/bash
# Quick n' dirty nvidia hack for kernel-xen
# REF: http://www.nvnews.net/vbulletin/showthread.php?t=68648
# Tested for kernel-xen 2.6.16.13-4 ( SUSE 10.1 - x86 ) using nvidia 1.0-8762
# cenuij@gmail.com

REQUIRED_PACKAGES="kernel-source kernel-xen gcc make glibc-devel module-init-tools gzip wget binutils"
KERNEL_XEN_VERSION=`uname -r`
SYMBOL_MAP="/boot/System.map-$KERNEL_XEN_VERSION"
NV_VERSION="8762"
SYSTEM_ARCH=`uname -m`

function error_die {
echo -e "ERROR: $*" >&2;
exit 1;
}

# Check for root, architecture and runlevel
[ "$UID" = "0" ] || error_die "Please run this script as root"
ps -C X &>/dev/null && die "Your X server is currently running, please run this script from runlevel 3"
case $(uname -m) in
x86_64) NV_ARCH=x86_64 ;;
i?86) NV_ARCH=x86 ;;
*) error_die "Architecture not supported: $SYSTEM_ARCH"
esac

# Check user has basic packages installed
echo -n "Checking installed packages"
missing=""
for package in $REQUIRED_PACKAGES; do
rpm -q "$package" &>/dev/null || missing="$missing $package"
echo -n "."
done
if [ -n "$missing" ]; then
echo -e "ERROR:\nThe following package(s) is/are missing:" >&2
for m in $missing; do
echo " $m" >&2
done
echo >&2
echo "Please install these packages then run this script again" >&2
exit 1
fi

# Extract the driver package, assuming it exists
./NVIDIA-Linux-$NV_ARCH-1.0-$NV_VERSION-pkg1.run --extract-only --target /tmp/NV-$NV_VERSION || error_die "Failed to extract the driver package NVIDIA-Linux-$NV_ARCH-1.0-$NV_VERSION-pkg1.run, please check this file exists and try again"

# Fetch the patch and apply
echo -e "Retrieving nvidia patch..."
wget "http://www.nvnews.net/vbulletin/attachment.php?attachmentid=17583&d=1145325458" &>/dev/null || error_die "Failed to download the nvidia driver patch"
mv "attachment.php?attachmentid=17583&d=1145325458" /tmp/NV-$NV_VERSION/patch-nv-8762.diff
cd /tmp/NV-$NV_VERSION/usr/src/nv
patch -p1 < /tmp/NV-$NV_VERSION/patch-nv-8762.diff

# Build precompiled module
make nv-linux.o mkprecompiled --interface=nv-linux.o --output=nv-linux.o-1.0-$NV_VERSION.suse-10.1-$KERNEL_XEN_VERSION \
--description="Quick n dirty for kernel-xen" \
--proc-version="`cat /proc/version`" \
--major=1 --minor=0 --patch=$NV_VERSION
mv nv-linux.o-1.0-$NV_VERSION.suse-10.1-$KERNEL_XEN_VERSION precompiled/

# Insert missing symbols
for sym in xen_tlb_flush force_evtchn_callback xen_features; do
export $sym=$(egrep " $sym\$" $SYMBOL_MAP | colrm 9)
done
ld -m elf_i386 --defsym xen_tlb_flush=0x$xen_tlb_flush \
--defsym force_evtchn_callback=0x$force_evtchn_callback \
--defsym xen_features=0x$xen_features \
-r -o nvidia.ko nvidia.o nvidia.mod.o

# Install other required NVIDIA binaries
echo "Installing NVIDIA driver support binaries"
cd /tmp/NV-$NV_VERSION
./nvidia-installer --silent --no-kernel-module

# Install and load the module
cp usr/src/nv/nvidia.ko "/lib/modules/$KERNEL_XEN_VERSION/kernel/drivers/video"
depmod -a $KERNEL_XEN_VERSION
echo "Installing NVIDIA driver kernel module"
modprobe nvidia || die "ERROR: Failed to load the NVIDIA kernel module"
rm -Rf /tmp/NV-$NV_VERSION
switch2nvidia
echo "Success!"

Additional Help

Additional help for SUSE Linux 10.1 can be found on the mailing lists or alternatively you can drop by the IRC chat channel #suse on freenode IRC network. If you are using KDE in SUSE Linux 10.1 then the IRC chat client Konversation is already configured to connect to the #suse channel on freenode IRC network.