Thursday 1st March 2012
This morning, I did something unquestionably naughty, and totally got away with it.
A little background. We just had some *brand* new workstations delivered.. They turned up yesterday afternoon. They're high performance 3d workstations with an Intel DX79TO mainboard. This mainboard has the intel 87529 Gigabit Ethernet controller. I wouldn't normally pay so much attention to the controllers and so on that are actually on a board, but in future, I will.
This controller is not supported by the e1000 driver that comes in the PXE installer on the netboot CD for Ubuntu 10.04.
We plugged them in, fired them up, and watched the PXE installer fail as it couldn't find a supported kernel module for that hardware. Bugger.
Our primary plan was to buy some cheap 1GE NICs, install with those, update the driver then carry on.
My personal plan was to update the initramfs of the PXE installer, give it a newer e1000 kernel module, and *pray* that it works.
Things you need.
2) The initrd.gz and linux files from the pxe installer.
3) The linux-headers for the kernel of the pxe boot installer
So go ahead and grab those initrd.gz and 'linux' files, then run `file` on 'linux' and grab the kernel version. Now you can download the headers for that version.
If you have a look inside the Makefile for the e1000e drivers, there's this block
ifeq (,$(BUILD_KERNEL))
BUILD_KERNEL=$(shell uname -r)
endif
which I read, and thought "Ha! I can provide BUILD_KERNEL as an environment variable and build against that instead."
BUILD_KERNEL=2.6.32-21-generic make
If you run make install, then it'll insert it into your own kernel. If you just run make, you can look in the src directory, and find the .ko file we need.
Then comes the harder part.
Make some directories like
kernelhacking/{initrd,e1000e}
copy the initrd.gz into initrd/
and run
zcat initrd.gz | (while true; do cpio -i -d -H newc --no-absolute-filenames || exit; done)
I lifted this little snippet from some guy's blog on the subject.
then mv the initrd.gz up a level.
Now you've got the rootfs that the installer uses.
[email protected]:~/kernelhacking/initrdhacking$ ls -lah
total 544K
drwxrwxr-x 15 tom.oconnor dialout 2.0K 2012-03-01 11:35 .
drwxrwxr-x 5 tom.oconnor dialout 2.0K 2012-03-01 13:40 ..
drwxr-xr-x 2 root root 8.0K 2012-03-01 11:35 bin
drwxr-xr-x 2 root root 2.0K 2012-03-01 11:35 dev
drwxr-xr-x 13 root root 4.0K 2012-03-01 11:50 etc
-rwxr-xr-x 1 root root 376 2012-03-01 11:35 init
drwxr-xr-x 2 root root 2.0K 2012-03-01 11:35 initrd
drwxr-xr-x 12 root root 4.0K 2012-03-01 11:35 lib
lrwxrwxrwx 1 root root 4 2012-03-01 11:35 lib64 -> /lib
drwxr-xr-x 2 root root 2.0K 2012-03-01 11:35 media
drwxr-xr-x 2 root root 2.0K 2012-03-01 11:35 mnt
drwxr-xr-x 2 root root 2.0K 2012-03-01 11:35 proc
drwxr-xr-x 2 root root 4.0K 2012-03-01 11:35 sbin
drwxr-xr-x 2 root root 2.0K 2012-03-01 11:35 sys
drwxr-xr-x 2 root root 2.0K 2012-03-01 11:35 tmp
drwxr-xr-x 6 root root 2.0K 2012-03-01 11:35 usr
drwxr-xr-x 8 root root 2.0K 2012-03-01 11:35 var
[email protected]:~/kernelhacking/initrdhacking$
The driver we want to replace is the e1000e.ko, deep within
lib/modules//kernel/drivers/net/e1000e.
I'm going to switch to root now, to save on sudo keystrokes:
[email protected]:/home/tom.oconnor/kernelhacking/initrdhacking/lib/modules/2.6.32-21-generic/kernel/drivers/net/e1000e# ls
e1000e.ko
[email protected]:/home/tom.oconnor/kernelhacking/initrdhacking/lib/modules/2.6.32-21-generic/kernel/drivers/net/e1000e# mv e1000e.ko /home/tom.oconnor/kernelhacking/old-e1000e.ko
[email protected]:/home/tom.oconnor/kernelhacking/initrdhacking/lib/modules/2.6.32-21-generic/kernel/drivers/net/e1000e# cp /home/tom.oconnor/kernelhacking/src/e1000e-1.9.5/src/e1000e.ko .
I also found a pci.ids update file in the e1000 package. Let's track that down, or at least figure out where it gets installed to.
[email protected]:~$ locate pci.ids
/usr/share/misc/pci.ids
[email protected]:/home/tom.oconnor/kernelhacking/initrdhacking# cd usr/share/misc/
[email protected]:/home/tom.oconnor/kernelhacking/initrdhacking/usr/share/misc# ls
pci.ids.gz
[email protected]:/home/tom.oconnor/kernelhacking/initrdhacking/usr/share/misc# zless pci.ids.gz
[email protected]:/home/tom.oconnor/kernelhacking/initrdhacking/usr/share/misc# gunzip pci.ids.gz
[email protected]:/home/tom.oconnor/kernelhacking/initrdhacking/usr/share/misc# ls
pci.ids
[email protected]:/home/tom.oconnor/kernelhacking/initrdhacking/usr/share/misc# vim pci.ids
[email protected]:/home/tom.oconnor/kernelhacking/initrdhacking/usr/share/misc# ls -lah
total 448K
drwxr-xr-x 2 root root 2.0K 2012-03-01 11:42 .
drwxr-xr-x 10 root root 2.0K 2012-03-01 11:35 ..
-rw-r--r-- 1 root root 358K 2012-03-01 11:35 pci.ids
[email protected]:/home/tom.oconnor/kernelhacking/initrdhacking/usr/share/misc# pwd
/home/tom.oconnor/kernelhacking/initrdhacking/usr/share/misc
[email protected]:/home/tom.oconnor/kernelhacking/initrdhacking/usr/share/misc# ls
pci.ids
[email protected]:/home/tom.oconnor/kernelhacking/initrdhacking/usr/share/misc# rm pci.ids
[email protected]:/home/tom.oconnor/kernelhacking/initrdhacking/usr/share/misc# wget http://pciids.sourceforge.net/v2.2/pci.ids.gz
--2012-03-01 10:49:50-- http://pciids.sourceforge.net/v2.2/pci.ids.gz
Resolving pciids.sourceforge.net... 216.34.181.96
Connecting to pciids.sourceforge.net|216.34.181.96|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 190157 (186K) [application/x-gzip]
Saving to: `pci.ids.gz'
100%[=======================================>] 190,157 242K/s in 0.8s
2012-03-01 10:49:51 (242 KB/s) - `pci.ids.gz' saved [190157/190157]
[email protected]:/home/tom.oconnor/kernelhacking/initrdhacking/usr/share/misc# ls -lah
total 256K
drwxr-xr-x 2 root root 2.0K 2012-03-01 11:49 .
drwxr-xr-x 10 root root 2.0K 2012-03-01 11:35 ..
-rw-rw-r-- 1 root root 186K 2012-02-27 02:15 pci.ids.gz
I couldn't be arsed patching the existing pci.ids, so I thought it would be just as good to replace it with the latest one from http://pciids.sourceforge.net/
Turns out, it is!
The next thing to do is to rebuild the initramfs back into a cpio.gz file.
I grabbed most of my initrd fu from here. It's a little out of date, perhaps, but seemed to work for me.
Let's say we've got this
[email protected]:/home/tom.oconnor/kernelhacking/initrdhacking# ls
bin dev etc init initrd lib lib64 media mnt proc sbin sys tmp usr var
First things first
$ touch initrdhacking/etc/mdev.conf
That's actually the only bit I had to do, and I only did it for compatibility reasons. The rest is all there, as we took it from a working initrd.gz file.
The compress bit was the bit i didn't quite know about.
cd initrdhacking
find . | cpio -H newc -o > ../initrd.cpio
cd ..
gzip initrd.cpio
Then we'll copy the new initrd.gz in place of the old one on the tftp server. You should always make a backup of the old one, in case this all goes horribly wrong, etc.
cd /tftpboot/ubuntu-1004-installer/amd64/
mv initrd.gz old.initrd.gz
cp /home/tom.oconnor/kernelhacking/initramfs.cpio.gz initrd.gz
Done.
I went over to the new workstations, and kicked them into a PXE netboot/preseed session.
:D. They're installing. Best feeling ever.
I stuck my hands in an initramfs and fiddled with it's private parts.
Epic Win.
See Part Two for the continuing saga of the e1000e kernel module.
There is no 'Ctrl' button on Tom's computer. He is always in control.