Nixpanic's Blog

Configuring the BeagleBoard to have network over usb0

After some experimenting, I have a kernel .config based on the kernel from the Angstrom BeagleBoard Demo. The original provided kernel with gether did not boot on my (loaned) BeagleBoard Rev B5. Only after disabling USB completely (kernel parameter nousb). As gether is the part I am most interested in, booting without USB is pretty pointless. Fortunately the kernel provides /proc/config.gz. Using this configuration, some little tuning (i.e. turning off the staging-modules because they do not compile), a kernel and suitable modules could be built.

Fedora almost expects using a initramfs for booting, and well, it surely makes troubleshooting easier! Getting dracut to run on a system where no network is available takes quite a lot of reboots (the BeagleBoard has one SD-slot for the filesystem, one mini-USB for power, a serial port for the console and nothing else that makes transport of files easy). Installing all the dependencies and disabling some dracut-modules /etc/dracut.conf (crypt dmraid mdraid multipath plymouth) in /etc/dracut.conf allows creating an initramfs.img. Before u-boot can use the initramfs.img, it needs to be converted with a command like:
# mkimage -A arm -O linux -T ramdisk -C none -e 0 -a 0 -n initramfs-2.6.38 -d /boot/initramfs-2.6.38.img /boot/uinitramfs-2.6.38.img

Currently, the generated files are on a VFAT-partition on an SD-card. This BeagleBoard boots from this card and uses the following settings to start the Fedora 13 ARM system:
OMAP3 beagleboard.org # printenv bootargs
bootargs=console=ttyO2,115200n8 root=/dev/mmcblk0p2 ro

OMAP3 beagleboard.org # printenv bootcmd
bootcmd=mmcinit ; fatload mmc 0:1 0x80000000 uimage-2.6.38 ; fatload mmc 0:1 0x81600000 uinitramfs-2.6.38.img ; bootm 0x80000000 0x81600000

OMAP3 beagleboard.org # boot

During boot, there are some messages that indicate that Ethernet-over-USB will be available:
[ 0.334960] musb-hdrc: version 6.0, musb-dma, otg (peripheral+host), debug=0
[ 0.335571] musb-hdrc musb-hdrc: USB OTG mode controller at fa0ab000 using DMA, IRQ 92
...
[ 4.824340] g_ether gadget: using random self ethernet address
[ 4.830505] g_ether gadget: using random host ethernet address
[ 4.837341] usb0: MAC ba:98:d2:e3:60:36
[ 4.841430] usb0: HOST MAC 4a:49:17:92:63:df
[ 4.846008] g_ether gadget: Ethernet Gadget, version: Memorial Day 2008
[ 4.853027] g_ether gadget: g_ether ready
[ 4.857269] musb-hdrc musb-hdrc: MUSB HDRC host driver
[ 4.863220] musb-hdrc musb-hdrc: new USB bus registered, assigned bus number 2
[ 4.885742] usb usb2: New USB device found, idVendor=1d6b, idProduct=0002
[ 4.892913] usb usb2: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[ 4.900543] usb usb2: Product: MUSB HDRC host driver
[ 4.905792] usb usb2: Manufacturer: Linux 2.6.38 musb-hcd
[ 4.911499] usb usb2: SerialNumber: musb-hdrc
...
[ 5.383911] g_ether gadget: full speed config #1: CDC Ethernet (ECM)

The musb-hdrc is the controller-chip and the g_ether is the implementation of the USB-client side of the USB-over-Ethernet gadget. On my laptop the BeagleBoard gets detected as a "RNDIS/Ethernet Gadget" product from vendor "Linux 2.6.38 with musb-hdrc":
usb 1-1: new high speed USB device using ehci_hcd and address 66
usb 3-1: new full speed USB device using uhci_hcd and address 45
usb 3-1: not running at top speed; connect to a high speed hub
usb 3-1: New USB device found, idVendor=0525, idProduct=a4a2
usb 3-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
usb 3-1: Product: RNDIS/Ethernet Gadget
usb 3-1: Manufacturer: Linux 2.6.38 with musb-hdrc
cdc_ether 3-1:1.0: usb0: register 'cdc_ether' at usb-0000:00:1a.0-1, CDC Ethernet Device, 4a:49:17:92:63:df
usb0: no IPv6 routers present
device usb0 entered promiscuous mode
virbr0: topology change detected, propagating
virbr0: port 1(usb0) entering forwarding state

The last lines are automatically triggered by my ifplugd-configuration which checks for usb0 devices and on a link, the usb0 is added to the virbr0 from libvirt so that BeagleBoard immediately gets access to the network.

On the side of the BeagleBoard, /etc/sysconfig/network-scripts/ifcfg-usb0 is configured to request an IP-address over DHCP:
DEVICE="usb0"
BOOTPROTO="dhcp"
ONBOOT="yes"
MACADDR="ba:98:d2:e3:60:36"

I prefer to give the BeagleBoard the same MAC-address on every boot, by default it is a random one. Setting MACADDR in ifcfg-usb0 makes this happen. The g_ether kernel-module accepts a MAC-address as parameter, but as the module is builtin, this is not convenient (pass g_ether.dev_addr as kernel parameter, or echo it to /sys/module/g_ether/parameters/dev_addr).

Enabling the network on boot and activating usb0 was the only thing left todo:
# chkconfig network on
# ifup usb0

The compiled kernel, initramfs and modules are available for download and re-use. Please report any issues or success if you try them out.

Now this is all written down, it seems really easy and quick. Keep in mind that compiling a very minimal kernel takes at least 120 minutes on the BeagleBoard, the kernel and modules from the Angstom distribution took much more... The BeagleBoard has since gained the elevated status of a mock-builder and rebuild java-1.5.0-gcj-1.5.0.0-32.fc13.bootstrap.src.rpm in "138 minutes 22 seconds", yay!

Creating a bootable USB-stick

This is a short explanation on how to create a bootable USB-stick with GRUB. This stick can be used to boot an installer, rescue-mode or an on-stick installed Linux distribution.

I mainly use my USB-stick to install different versions (and architectures) of RHEL. Booting from this USB-stick and starting and starting a kickstart installation is really convenient.

Detect the USB-stick

This is a very important step and the one where most attention is needed. Detecting the device-node where the USB-stick is connected should not go wrong. Picking the wrong drive will not make your system unbootable (as we're creating a bootable disk), but all data will be lost!

To detect which device-node is used for the USB-stick, I tend to check the output from the command 'dmesg'. This commmand displays the contents of the kernel-log-buffer and the last lines contain the last events. Insert the USB-stick and shortly after that checking 'dmesg', results for me in the following output (truncated here, only the last importan messages are shown):
usb 1-2: new high speed USB device using ehci_hcd and address 5
usb 1-2: New USB device found, idVendor=1e3d, idProduct=2093
usb 1-2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 1-2: Product:
usb 1-2: Manufacturer: USB 2.0
usb 1-2: SerialNumber: 26073604A307E205
usb 1-2: configuration #1 chosen from 1 choice
scsi4 : SCSI emulation for USB Mass Storage devices
usb-storage: device found at 5
usb-storage: waiting for device to settle before scanning
usb-storage: device scan complete
scsi 4:0:0:0: Direct-Access USB 2.0 5.00 PQ: 0 ANSI: 2
sd 4:0:0:0: Attached scsi generic sg2 type 0
sd 4:0:0:0: [sdc] 4067328 512-byte logical blocks: (2.08 GB/1.93 GiB)
sd 4:0:0:0: [sdc] Write Protect is off
sd 4:0:0:0: [sdc] Mode Sense: 0b 00 00 08
sd 4:0:0:0: [sdc] Assuming drive cache: write through
sd 4:0:0:0: [sdc] Assuming drive cache: write through
sdc: sdc1 sdc2
The USB-stick just connected is called 'sdc' and obviously contiains two partitions: sdc1 and sdc2. The matching device-node for this USB-stick is '/dev/sdc'.

Prtitioning the USB-stick

There exist a lot of tools to perform partitioning of a disk. One of the most common tools is 'fdisk' and that is very esy to use, therefore I mostly use this tool too.

'fdisk' takes the device-node as parameter, starting 'fdisk' looks like this:
# fdisk /dev/sdc

The number of cylinders for this disk is set to 32280.
There is nothing wrong with that, but this is larger than 1024,
and could in certain setups cause problems with:
1) software that runs at boot time (e.g., old versions of LILO)
2) booting and partitioning software from other OSs
(e.g., DOS FDISK, OS/2 FDISK)

Command (m for help):
In order to make the USB-stick usable on a lot of systems, it seems to be a good idea to create a MSDOS-partitiontable on it.
Command (m for help): o
Building a new DOS disklabel with disk identifier 0x077c807a.
Changes will remain in memory only, until you decide to write them.
After that, of course, the previous content won't be recoverable.

The number of cylinders for this disk is set to 32280.
There is nothing wrong with that, but this is larger than 1024,
and could in certain setups cause problems with:
1) software that runs at boot time (e.g., old versions of LILO)
2) booting and partitioning software from other OSs
(e.g., DOS FDISK, OS/2 FDISK)
Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite)
The only purpose of this stick will be that it is able to boot a range of kernels. Using it to save or transfer files is not important and therefore this stick will contain one VFAT partition. This makes it possible to add files and change the configuration under practically any operating system.

Create one primary partition:
Command (m for help): n
Command action
e extended
p primary partition (1-4)
p
The partition should be the first partition:
Partition number (1-4): 1
The start of the partition should be the first cylinder on the disk:
First cylinder (1-32280, default 1):
Using default value 1
By default the size of the partition will be the whole disk:
Last cylinder, +cylinders or +size{K,M,G} (1-32280, default 32280):
Using default value 32280
Change the type of the partition:
Command (m for help): t
Selected partition 1
VFAT is most portable, so choose 'c' (the hex-value for VFAT):
Hex code (type L to list codes): c
Changed system type of partition 1 to c (W95 FAT32 (LBA))
Mark the newly created partition bootable (probably not needed though):
Command (m for help): a
Partition number (1-4): 1
Check if all has been configured correctly, nothing has been saved yet:
Command (m for help): p

Disk /dev/sdc: 2082 MB, 2082471936 bytes
2 heads, 63 sectors/track, 32280 cylinders
Units = cylinders of 126 * 512 = 64512 bytes
Disk identifier: 0x077c807a

Device Boot Start End Blocks Id System
/dev/sdc1 * 1 32280 2033608+ c W95 FAT32 (LBA)
If all looks okay, write the changes to the partitiontable on the disk:
Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.
After this, the kernel got instructed to read the new partitiontable. The result should be that there is a new /dev/sdc1. Before this new partition can be used, it should be formatted:
# mkfs -t vfat -n ndevos /dev/sdc1
With the new filesystem on the USB-stick, it is now possible to mount the stick:
# mount /dev/sdc1 /mnt
and copy the required files for the bootloader:
# mkdir -p /mnt/boot/grub
# cp /boot/grub/* /mnt/boot/grub/
Before the bootlaoder can get installed in the Master Boot Record (MBR), it needs to get mapped, so that GRUB recognises the USB-stick as first bootable disk. This can be done by changing the device.map file (or creating it if missing):
[root@localhost ~]# cat /mnt/boot/grub/device.map
# this device map was generated by ndevos on eeepc
(hd0) /dev/sdc
This example shows that (hd0) is mapped to /dev/sdc.

Installing GRUB with the updated device.map file is done like this:
# grub --device-map=/mnt/boot/grub/device.map


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 (hd0,0)
root (hd0,0)
Filesystem type is fat, partition type 0xc
grub> setup (hd0)
setup (hd0)
Checking if "/boot/grub/stage1" exists... yes
Checking if "/boot/grub/stage2" exists... yes
Checking if "/boot/grub/fat_stage1_5" exists... yes
Running "embed /boot/grub/fat_stage1_5 (hd0)"... 27 sectors are embedded.
succeeded
Running "install /boot/grub/stage1 (hd0) (hd0)1+27 p (hd0,0)/boot/grub/stage2 /boot/grub/grub.conf"... succeeded
Done.
grub> quit
quit
The USB-stick does now contain a working GRUB and can be used to bootstrap an installer (or rescue disk) for any Fedora, RHEL and possibly other Linux distributions. The only two things that needs to be done before this works are
  1. copy the vmlinz and initrd.img to the /mnt/boot directory
  2. update the /mnt/boot/grub/grub.conf with lines to boot the new kernel (with any options you like) with the matching initrd