GRUB PXE network boot

From LinuxMCE
Revision as of 02:29, 26 July 2007 by Zaerc (Talk | contribs) (PXE boot using GRUB, as requested)

(diff) ←Older revision | view current revision (diff) | Newer revision→ (diff)
Jump to: navigation, search

As an alternative way to boot a diskless Media Director the bootloader GRUB can be used.

The bootloader GRUB is able to boot using PXE as well, this can be a great alternative way to boot (diskless) Media Directors for several reasons.

  1. The machine does not support PXE booting directly (no boot-ROM).
  2. You can use a GRUB bootmenu to decide wheter you want to boot LMCE or the native OS.
  3. Booting is a lot faster when you boot the native OS by skipping the network step.
  4. GRUB allows for easy adjustments of the boot parameters at boottime.

Prerequisites

  1. The GRUB sources.
  2. A development environment capable of building GRUB from source.
  3. Knowing which (supported) ethernet adapter is in the machine you want to boot.

Getting started

  1. Untar the GRUB sources somewhere and move into the newly created directory.
  2. Read The netboot/README.netboot file for additional information on what to specify for which network adapter.
  3. Configure the GRUB build
  4. Build GRUB from source.

In a nutshell, using grub-0.97 with my old Realtek 8139 (which you can buy just about anywhere for a few bucks):

tar xvf grub-0.97.tar.gz
cd grub-0.97
less netboot/README.netboot # make a note of the option you need for your network interface
./configure --prefix=/usr --enable-diskless --enable-rtl8139 # That's the one I needed
make # if this fails see "known problems" below for a possible fix.

WARNING: Do not run make install (as root) unless you want this version to overwrite the existing one on your system.

Installing

You have several options here, basicly this version of GRUB works just like the regular version so it can be put on floppy, USB stick, CDRom, Harddrive, etcertera. Please add other examples as you try them.

Installing on a Floppy using the "extended-2" (ext2fs) filesystem

A better way to do this would be to use the minix-filesystem to save some precious space, one might even be able to squeeze a kernel in, but ext2fs fits my needs as all I want is GRUB so I couldn't be bothered. Before doing this you should have moved to the directory where you built GRUB, obtained root privileges and inserted a writable floppy disk in the drive, WARNING:it's current contents will be lost during this procedure unless you skip the first step.

  1. format the floppy
  2. create a directory to mount it on
  3. mount the floppy
  4. install GRUB on the floppy directly
  5. create the boot/grub directory on the floppy
  6. hard link some files into the boot/grub directory
  7. copy the example menu.lst
  8. install GRUB onto the bootsector of the floppy
mkfs.ext2 /dev/fd0
mkdir -pv floppy
mount /dev/fd0 floppy
make install DESTDIR=`pwd`/floppy
mkdir -pv floppy/boot/grub
ln -v floppy/usr/lib/grub/i386-pc/{stage1,e2fs_stage1_5,stage2} floppy/boot/grub/
cp -v docs/menu.lst floppy/boot/grub
umount floppy
grub/grub
    GNU GRUB  version 0.97  (640K lower / 3072K upper memory)

 [ Minimal BASH-like line editing is supported.  For the first word, TAB
   lists possible command completions.  Anywhere else TAB lists the possible
   completions of a device/filename. ]

 grub> root (fd0)
  Filesystem type is ext2fs, using whole disk
 
 grub> setup (fd0)
  Checking if "/boot/grub/stage1" exists... yes
  Checking if "/boot/grub/stage2" exists... yes
  Checking if "/boot/grub/e2fs_stage1_5" exists... yes
  Running "embed /boot/grub/e2fs_stage1_5 (fd0)"... failed (this is not fatal)
  Running "embed /boot/grub/e2fs_stage1_5 (fd0)"... failed (this is not fatal)
  Running "install /boot/grub/stage1 (fd0) /boot/grub/stage2 p /boot/grub/menu.lst "... succeeded
 Done.
 
 grub> quit

You should be all set now, only thing left is to edit the menu.lst file to your liking.

Configuring GRUB to boot from the network

You will need to edit the boot/grub/menu.lst file for this.

This is an example for adding a new Media Director. First I added this as the top "target":

title New Media Director
dhcp
root (nd)
kernel /tftpboot/default/vmlinuz root=/dev/nfs acpi=off vga=normal ramdisk_size=10240 rw ip=all apicpmtimer
initrd /tftpboot/default/initrd

And here is what I added above that for one of my Media Directors (device #100), lateron after it was added to the system:

title moon100
dhcp
root (nd)
kernel /tftpboot/100/vmlinuz ramdisk=10240 rw root=/dev/nfs boot=nfs nfsroot=192.168.80.1:/usr/pluto/diskless/100
initrd /tftpboot/100/initrd.img

After modifying the boot/grub/menu.lst there is no need to run or install GRUB itself again. This floppy can now be used not only to boot but also to install GRUB on other systems or media.


Known Problems

Building fails with newer version of GCC

When using version 0.97 in combination with a modern version of the Gnu Compiler Collection (GCC) the build is likely to fail, which goes a little like this:

make[2]: Entering directory `/mnt/sda8/usr/src/PMS/Building/grub-0.97/netboot'
if gcc -DHAVE_CONFIG_H -I. -I. -I.. -I../stage2 -I../stage1  -Wall -Wmissing-prototypes -Wunused -Wshadow -Wpointer-arith -falign-jumps=1 -falign-loops=1 -falign-functions=1 -Wundef -Os -fno-stack-protector -fno-builtin -nostdinc -DFSYS_TFTP=1 -DINCLUDE_RTL8139=1 -DCONGESTED=1 -DNE_SCAN=0x280,0x300,0x320,0x340 -DWD_DEFAULT_MEM=0xCC000 -g -MT libdrivers_a-main.o -MD -MP -MF ".deps/libdrivers_a-main.Tpo" -c -o libdrivers_a-main.o `test -f 'main.c' || echo './'`main.c; \
       then mv -f ".deps/libdrivers_a-main.Tpo" ".deps/libdrivers_a-main.Po"; else rm -f ".deps/libdrivers_a-main.Tpo"; exit 1; fi
main.c:57: error: static declaration of 'bootp_data' follows non-static declaration
./etherboot.h:534: error: previous declaration of 'bootp_data' was here
main.c:59: error: static declaration of 'end_of_rfc1533' follows non-static declaration
./etherboot.h:536: error: previous declaration of 'end_of_rfc1533' was here
main.c: In function 'udp_transmit':
main.c:231: warning: pointer targets in passing argument 1 of 'eth_transmit' differ in signedness
main.c:276: warning: pointer targets in passing argument 1 of 'eth_transmit' differ in signedness
main.c:290: warning: pointer targets in passing argument 1 of 'eth_transmit' differ in signedness
main.c: In function 'tftp':
main.c:462: warning: pointer targets in passing argument 1 of 'fnc' differ in signedness
main.c: In function 'rarp':
main.c:509: warning: pointer targets in passing argument 1 of 'eth_transmit' differ in signedness
main.c: In function 'udpchksum':
main.c:729: warning: dereferencing type-punned pointer will break strict-aliasing rules
main.c: In function 'await_reply':
main.c:893: warning: pointer targets in passing argument 1 of 'grub_memcmp' differ in signedness
main.c:895: warning: pointer targets in passing argument 1 of 'grub_memcmp' differ in signedness
main.c:925: warning: pointer targets in passing argument 1 of 'decode_rfc1533' differ in signedness
main.c: In function 'decode_rfc1533':
main.c:973: warning: pointer targets in passing argument 1 of 'grub_memcmp' differ in signedness
main.c:973: warning: pointer targets in passing argument 2 of 'grub_memcmp' differ in signedness
main.c:984: warning: pointer targets in passing argument 1 of 'grub_memcmp' differ in signedness
main.c:1057: warning: pointer targets in passing argument 1 of 'grub_memcmp' differ in signedness
main.c:1057: warning: pointer targets in passing argument 2 of 'grub_memcmp' differ in signedness
make[2]: *** [libdrivers_a-main.o] Error 1
make[2]: Leaving directory `/mnt/sda8/usr/src/PMS/Building/grub-0.97/netboot'
make[1]: *** [all-recursive] Error 1
make[1]: Leaving directory `/mnt/sda8/usr/src/PMS/Building/grub-0.97'
make: *** [all] Error 2

No need to panic, this is basicly just the GCC maintainers letting the GRUB developers know they need to clean up their code. Just throw (copy+paste) this command in the mix in order to fix the collateral damage:

patch -Np1 << EOF
--- grub-0.97.orig/netboot/main.c       2004-05-21 00:19:33.000000000 +0200
+++ grub-0.97/netboot/main.c    2007-07-20 02:31:28.000000000 +0200
@@ -54,9 +54,9 @@
 
 static int vendorext_isvalid;
 static unsigned long netmask;
-static struct bootpd_t bootp_data;
+struct bootpd_t bootp_data;
 static unsigned long xid;
-static unsigned char *end_of_rfc1533 = NULL;
+unsigned char *end_of_rfc1533 = NULL;

 #ifndef        NO_DHCP_SUPPORT
 #endif /* NO_DHCP_SUPPORT */
EOF

All this does is remove the keyword "static" from 2 lines of code. Now you can continue where it left off by issuing the make command again.

Can't I just use yours?

Sure, you can just download an image of the floppy I just created (whilst verifying these steps) and write it to a floppy:

dd if=grub-0.97--enable-diskless--enable-rtl8139.floppy.img of=/dev/fd0

Or mount it using a loopback device:

modprobe loop
mkdir floppy
mount grub-0.97--enable-diskless--enable-rtl8139.floppy.img floppy -o loop

Note however that this version will only recognize the Realtek 8139 network interface.