Adding driver modules to a Fedora Core 2 CD for kickstart install This document should take you through the steps required to create a kickstart boot CD for Fedora Core 2 that incorporates a driver module not present on the Fedora Core 2 install distribution. Our example module is the BroadCom-supplied bcm5700 driver for BroadCom GB Ethernet cards; Dell gx280s are shipping with a newer version of this card that is not recognized by the tg3 driver, which is why we wanted to do this. Note that we're focusing on building a netboot CD because we want to automate installs for a lot of similar equipment; this is probably more work than you're looking for if you just want to install a single machine. -------------------------------------------------------- I. Gathering preliminary info There are several pieces of information to gather before building the kickstart CD, for which it's useful to install the driver you're looking to incorporate on an existing system. Specifically, you want the PCI table string for the card, and pcimap and dependency information from /lib/modules/`uname-r`/modules.pcimap and modules.dep. A. PCI table info The kernel needs to be able to associate your new driver with the hardware it's meant to run, which means the card's PCI ID has to be in the PCI table. Boot a machine with the hardware installed using anything that gets you a linux console (knoppix, rescuecd, standalone install disks, whatever) and run lspci to find the hardware; it'll probably be listed as "unknown device" in the output from lspci. Look at the first fields, those correspond to the physical location (bus:slot.function) and remember them. Now run "lspci -n" and find the line that corresponds to the location you just saw for the new hardware. The PCI id is the fourth field, and should consist of two four-digit hexadecimal numbers separated by a colon. The bcm card we were trying to use looked like this: 02:00.0 Class 0200: 14e4:1677 (rev 01) The important numbers here are "14e4" (the vendor ID) and "1677" (the device ID). You'll need these in step III. B. Pcimap info For the pcimap information, grep out all the lines beginning with the module name and save them to a file:: grep ^bcm5700 > /tmp/bcm5700.pcimap C. Module dependencies For the dependency information, you'll need to massage the data by removing all the pathing from each element (note that the bcm5700 module has no dependencies, so this is untested): tstr=""; for i in `grep -E ^[^[:space:]]*/bcm5700.ko modules.dep`; \ do tstr="$tstr `basename $i`"; done ; echo $tstr > bcm5700.dep You'll want the .dep and .pcimap files thus created when you're ready to repack the bootcd iso tree in (III.D) below. -------------------------------------------------------- II. Building the Modules A. kernel environment First, we need to build a module binary (.ko file) that is compatible with the FC2 install kernel. To do that, we need a kernel build environment that replicates the one used to build the install kernel. On a newly-installed FC2 system: - install the kernel-sources rpm for 2.6.5-1.358 - cd /usr/src/linux-2.6.5-1.358 - make clean - cp configs/kernel-2.6.5-i586.config .config - perl -p -i -e 's/8custom/8/g' Makefile - make oldconfig - make modules (may not be necessary, but what the hell) B. Build the module itself Now you're ready to build your custom module. In the case of our bcm5700 driver, it came as a source rpm; we installed the src.rpm, and then ran "rpmbuild -bp /usr/src/redhat/SPECS/bcm5700.spec" which does the unpack and source prep stages of the RPM build. Then we changed into the build directory ("cd /usr/src/redhat/BUILD/bcm5700") and investigated the Makefile. The key step here is making sure that the module builds using the kernel tree you've just prepared, and doesn't try to grab information from the running kernel (looking in /lib/modules/`uname -r`/build, for example.) For the bcm5700, we found this was possible by adding "LINUX=/usr/src/linux-2.6.5-1.358" to the make arguments: "make LINUX=/usr/src/linux-2.6.5-1.358 bcm5700.ko" -- YMMV. Once you have a kernel object (ko) file, make sure it has the right versioning magic; run strings on it and grep in the output for "vermagic". The result should be "2.6.5-1.358 586 REGPARM 4KSTACKS gcc-3.3" as shown here: [root@host /tmp]# strings bcm5700.ko | grep verm vermagic=2.6.5-1.358 586 REGPARM 4KSTACKS gcc-3.3 [root@host /tmp]# -------------------------------------------------------- III. Rebuilding the ISO Ok, now we need to put our new module into the initrd used by the boot iso. (Note that the "boot iso" is not the same CD as the 1st FC2 install CD -- rather, it's the image "boot.iso" contained on that CD in the "images directory.) For this section, you don't need to be working directly on an FC2 box -- we used aroostook, an RH9 system which exports ISOs for several distros including FC2. A. Make a working copy of the boot iso structure 1. Mount the original boot iso using a loopback mount: - mount -t iso9660 -o loop /cds/fc2/d1/images/boot.iso /mnt/tmp 2. Copy the CD structure to a temporary location: - cp -r /mnt/tmp /tmp/fcboot 3. Remove the iso9660 translation tables (new ones will be added back in by mkisofs): - find /tmp/fcboot -name TRANS.TBL -exec rm -f {} \; B. Unroll and mount the initial ramdisk An initrd is just an ext2 partition image that's been gzipped, so to get at its contents and modify them we unzip and then use a loopback mount: - gzip -dc /tmp/fcboot/isolinux/initrd.img > /tmp/initrd.unz - mkdir /tmp/initrd - mount -o loop /tmp/initrd.unz /tmp/initrd C. Unroll the modules.cgz CPIO archive and add our new module Ever play with one of those one-inside-the-other russian dolls? This feels a little like that... The kernel modules are contained inside a gzipped CPIO archive within the initrd, I think primarily because CPIO provides CRC checking and is smaller than tar. - mkdir /tmp/modwork - cd /tmp/modwork - gzip -dc /tmp/initrd/modules/modules.cgz | cpio -id Now copy the new module into our working directory and repack the CPIO archive: - cp /tmp/bcm5700.ko 2.6.5-1.358/i586 - find * | cpio -o -H crc | gzip -9 > /tmp/initrd/modules/modules.cgz D. Add PCI/module information to initrd Now that our new module is part of the initrd, the kernel will be able to load it -- but it needs to know why it should. The answer is in the pci table; when the kernel scans the PCI bus, it will see the PCI vendor/device IDs (which we found in step (I.B) above) and it will crossreference those in the pcitable file. You'll need to add a line to this file so that the kernel will associate the PCI id with the module you're incorporating. 1. pcitable - edit /tmp/initrd/modules/pcitable, and add a line of the following format: "" "text string" where the IDs are hex numbers in 0x#### format. The text string is arbitrary, the whitespace is composed of TABS (*not* spaces) and the module name is bare (i.e. without the ".ko" suffix.) Here's the line we used for the BroadCom: 0x14e4 0x1677 "bcm5700" "Broadcom Corporation|NetXtreme BCM5700x Gigabit Ethernet" 2. modules.dep Append the dependency information you generated in step (I.C, above) to the modules.dep file: - cat /tmp/bcm5700.dep >> /tmp/initrd/modules/modules.dep 3. modules.pcimap Append the pcimap information you grepped in step (I.B, above) to the modules.pcimap file: - cat /tmp/bcm5700.pcimap >> /tmp/initrd/modules/modules.pcimap 4. modules.info If you like, add a stanza to module-info describing the hardware the module is supposed to drive. The one we added: bcm5700 eth "Broadcom NetXtreme 5700x Gigabit Ethernet" F. Repack it all into a new ISO image Ok, we're almost done; just have to put the dolls back together. "modules.cgz" is already done, so let's roll up the initrd and create a new CD image... 1. initrd - cd /tmp - umount /tmp/initrd - gzip -c /tmp/initrd.unz > /tmp/fcboot/isolinux/initrd.img 2. ISO - mkisofs -o fcboot.iso -b isolinux/isolinux.bin -c \ isolinux/boot.cat -no-emul-boot -boot-load-size 4 \ -boot-info-table -R -J -v -T /tmp/fcboot G. burn H. cross fingers I. test J. helpful links.... Much of this document was interpolated from Alexandre Oliva's firewire module work, particularly the add-modules script: http://www.ic.unicamp.br/~oliva/snapshots/FC2-firewire/add-modules