Grub and OpenEmbedded

Joe Pfeiffer --

I recently spent several weeks getting a Technologic Systems TS-5500 486-based single board computer to boot OpenEmbedded from a compact flash card. The following notes describe the sequence of operations that finally succeeded. Hopefully, they will be helpful to others trying to get openembedded running on other, similar SBCs.

Disclaimer: this information is the result of my own experience, and is released with the hope that it is useful. However, I make no warranty that it will also work on your system, and explicitly disclaim all liability for your results. Installing boot loaders is an inherently risky business; it's easy to imagine missing a step or mis-typing something resulting in corrupting the MBR on your workstation. That could turn into a Really Bad Day.

Note on device names:

On my workstation, the CF drive appears as /dev/sda and its first partition as /dev/sda1. Everything I say here will have to be modified to reflect your setup.

The most important changes will be to make sure the major and minor device numbers you set up in step 8 correspond to the actual CF card.

/dev/sda and /dev/sda1:
$ mknod /dev/sda b 8 0
$ mknod /dev/sda1 b 8 1

/dev/sdb and /dev/sdb1:
$ mknod /dev/sdb b 8 16
$ mknod /dev/sdb1 b 8 17

/dev/sdc and /dev/sdc1:
$ mknod /dev/sdc b 8 32
$ mknod /dev/sdc1 b 8 33

/dev/sdd and /dev/sdd1:
$ mknod /dev/sdd b 8 48
$ mknod /dev/sdd1 b 8 49

After that, of course, you need to subsitute the actual name of the device for /dev/sda and /dev/sda1 as appropriate.

The Easy Way: Installing My Image

New! I had a request for my CF image -- so I bzip2ed it, and here it is! You can put this on your CF card with the command

# bzcat cf.dd.bz2 | dd of=/dev/sda

(note: this is an image of a 512MB filesystem. If your CF card is too small, you'll get an error saying dd: writing to `/dev/sda': No space left on device and grub won't be able to boot your machine)

Of course, this approach only installs exactly my image on your board. I suppose that's useful for making sure it all really works... If you're going to create your own image and install it, you'll need to go down to the next section.

The Hard Way: Installing Your Image

Prerequisites: it is assumed that you've successfully installed openembedded, and have created a bootstrap-image for use with your SBC. Also, you'll need a CF adapter for your workstation.

On with the show:

  1. Partition CF with

    # cfdisk /dev/sda

    I created a single partition, with FS type 83 (Linux), marked as bootable.

  2. Copy openembedded bootable image to CF partition with

    # zcat openembedded/tmp/deploy/images/bootstrap-image-ts5500-20070306233119.rootfs.ext2.gz > /dev/sda1

    (of course, this will have to be modified to reflect the actual name of the bootstrap-image you will be installing. The important thing is that you will need to use the *.ext2.gz image). This may happen suspiciously quickly, for the reason to be noted in the next step:

  3. Important! Since /dev/sda1 is a block device, writes to it are cached.

    # sync

    This will take a while, as the writes from the last step actually take place now. note: the speed of these two steps seems to vary with the CF adapter used. At any rate, I've sometimes seen the zcat command finish in virtually no time while the sync takes several minutes, and I've seen it the other way around. Just do both!

  4. Mount the CF partition containing the openembedded filesystem with

    # mount /dev/sda1 /mnt

    Note: the disk must not be mounted noexec. in the procedure being described here, it isn't necessary to have grub installed on your workstation to get it on the CF -- we'll use the version on the CF itself. It would also be possible to install from the workstation's disk with minimal changes.

  5. Switch to execution from the CF. There is no bash shell in the openembedded bootstrap image I built, so I had to specify the shell.

    # chroot /mnt sh

    You are now executing commands from a "chroot jail" (note the change in prompt)

  6. Both Debian (the system I use on my workstation) and openembedded leave the files for grub in /usr/lib/grub/i386-pc/ but grub expects to find them in /boot/grub (I suppose it's to allow for people who have /boot on a separate partition). While it's possible to set it up from the former, life is much easier if we follow the installation instructions and copy the files we need.

    $ mkdir /boot/grub
    $ cp /usr/lib/grub/i386-pc/stage1 /boot/grub
    $ cp /usr/lib/grub/i386-pc/e2fs_stage1_5 /boot/grub
    $ cp /usr/lib/grub/i386-pc/stage2 /boot/grub
  7. Create a boot configuration file. Note: I'm sure I'm doing something wrong, but I can't get the vt100 emulation to work. I get invalid escape sequences (in particular, double-semicolons in the middle of cursor positioning). Consequently, I need to use the dumb terminal option to get things to work. Comments are in the file.

    $ cat > /boot/grub/menu.lst
    # use the serial terminal for the console.  The --unit is specifying
    # that it should use /dev/ttyS1, the speed is 115200
    serial --unit=1 --speed=115200
    # it's a dumb terminal.
    terminal --dumb serial
    # by default, boot menu entry 0.  There's no timeout, so we'll sit at
    # the prompt until the user hits "enter"
    default 0
    # start menu entry with title
    title openembedded GNU/linux
    # tell grub to find the kernel on /dev/hda1
    root (hd0,0)
    # the kernel needs to use ttyS1, same speed as grub.  Also, we need to
    # tell the kernel where to find its root filesystem.  Note the
    # different syntax for specifying the console and specifying the root.
    kernel /boot/bzImage console=ttyS1,115200 root=/dev/hda1
  8. In order to have access to the CF as a device, we need to create a special file for it on the CF itself. Note that the major and minor numbers must correspond to the major and minor numbers for the CFdisk on your workstation.

    $ mknod /dev/sda b 8 0
    $ mknod /dev/sda1 b 8 1

    When you're all done, you can delete these if you want. I didn't bother.

  9. Execute grub

    $ grub

    The following commands are executed from within grub (note the change in prompt)

  10. Map grub's internal idea of the first hard drive to /dev/sda. Now it'll use /dev/sda when installing the bootloader (but it'll still go to the onboard IDE interface at boot time)

    grub> device (hd0) /dev/sda

    Grub should respond with

    device (hd0) /dev/sda
  11. Tell grub it'll be booting from the first partition on the drive.

    grub> root (hd0,0)
  12. Grub should respond with

    root (hd0,0)
    Filesystem type is ext2fs, partition type 0x83
  13. Now install the bootloader

    grub> setup (hd0)

    Grub should respond with

    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 (hd0)"...  17 sectors are embedded.
    Running "install /boot/grub/stage1 (hd0) (hd0)1+17 p (hd0,0)/boot/grub/stage2 /boot/grub/menu.lst"... succeeded
  14. Exit grub

    grub> quit

    On my system, grub segfaults at this point. I imagine this is something Somebody should look into... or maybe some helpful soul will show me something I'm doing wrong.

  15. Get out of chroot jail.

    $ exit

    Note the change in prompt

  16. # umount /mnt
  17. Next step is to make sure the SBC's BIOS is set up correctly. It must be configured to boot from the CF drive (on the TS-5500 BIOS this is seen as drive C:), using AUTOCONFIG, LBA.

    I spent several days discoving this fact. My BIOS was initially set up using AUTOCONFIG, PHYSICAL (which I assume to mean CHS); the symptom was that when I tried to boot I saw GRUB GRUB GRUB GRUB repeated forever on my terminal emulator screen.

  18. With the CF in the SBC, and your favorite terminal emulator running on the SBC's serial port, your SBC should now successfully boot. At least mine does.

Last modified: Wed Nov 26 11:37:02 MST 2008