7/23/2014

PXE, Sys etherboot gPXE and iPXE


PXE has a long history

But essentially its a 16 Bit program that uses the environment setup by an x86 BIOS bootloader to then pull another bootloader across a network and then starts that.

PXE is a routine that implements a [step] on the way from boot a machine to executing an operating system.

BIOS gets a motherboard, systemboard, or pc computer running, from power on it tests then manually configures all the attached devices to make them ready for the programs that follow.

BIOS also has a long history, from the IBM PC to the Phoenix and AMI versions of the original up to the present day.

IBM published its BIOS code and the versions that came after used it as a means to produce a set of assumptions called the Application Program Interface (API) to then write code that could take over and continue the process of getting work done.

Microsoft wrote a "kernel" to take over this job and it had a driver API and a DOS programming API.

Linux had similar "kernels" and a choice of pre Linux kernel "bootloaders", Lilo, Grub, Syslinux

PXElinux is a variant of the last to pull the final Linux kernel piece over the network and start it up.

Etherboot was a project to place a netboot or PXE code in a network adapter ROM so that BIOS would chain to it and start it up, by-passing the need for a local mass storage device, or to rewrite the BIOS code such that it included these routines.

gPXE was an attempt to modularize and enhance Etherboot.

iPXE was a branch or fork from gPXE that took a different direction to do similar things

Meanwhile Syslinux continued to do what it did very well, it bootstraped existing BIOS boot devices from anything the BIOS could itself boot from, into later bootstrap or kernel code.

Syslinux support for iPXE was attempted to unify and benefit both, letting each specialize in what it did best.

Neither Syslinux or iPXE had code to support USB devices.. exactly, some BIOSes will support native Flash or Memory chips which are inserted into SD or USB slots for booting. But generally do not have generic support for all the possible types of USB devices that might be inserted into a slot connected to a USB controller that is supported by a BIOS.

A USB network adapter is a USB device with an Ethernet controller at the end of a USB cable. When it is inserted into a USB slot, the BIOS must recognize the event, then initalize or setup the device and support communications with it. Then any program that needs to use it for network communications, like a PXE routine, must further initialize the network controller across the USB bus for communications and then carry out a few simple operations to download and execute an additional bootstrap or kernel code.

In order to add USB network adapter support to the Syslinux or iPXE bootloader code, a driver needs to be created to seek out and start or work with a USB controller, then command it to find the USB network adapter on the USB bus and initialize it for communications and carry those communications out.

First we need a development platform.

Centos 5.9 i386 with EPEL for RHEL 5.4 enabled running in VMware Player will suffice.

Then we need a USB network adapter and a USB bus and controller to work with.

VMware Player is known for good USB 2.0 controller support.

So we can connect a USB network adapter to the VMware Player host and connect it to the virtual machine, then run the command "lsusb" to detect the USB device the Linux kernel detected upon insertion.


This obviously worked indicating I attached a ASIX AX87722A Fast Ethernet 10/100 Adapter

Technical documentation and driver source code for a Linux kernel is available here:

AX88772A Drivers Download

For Linux kernel 2.6.9 to 2.6.13 ( 9-11-2007 )

The driver source appears as a single .C file and .H header file that produces a single usbnet.ko module file which can be compiled and linked with linux kernel libraries and code to produce a driver to support the AX88772A chipset, taking advantage of the linux kernel support for the USB bus chipsets.

The [Readme] file in the source code tarball seems to indicate it supports both types of ASIX adapter
    ASIX AX88178 USB2.0 Gigabit Ethernet Network Adapter
    ASIX AX88772 USB2.0 Fast Ethernet Network Adapter
Balaji Rao already appears to have tried to add USB network adapter support to gPXE here

Enabling gPXE to use USB Ethernet Adapters

iPXE shares a common ancestry with gPXE, so it would make sense to investigate the approach he took and see if it could be used to enable iPXE to use USB Ethernet Adapters.

As far as I could tell (and this is second hand information) Balaji started the project inbetween jobs and ceased working on the project after acquiring a new position.

He did create a Git repository which can be checked out:

# git clone git://git.etherboot.org/people/balajirrao/gpxe.git -b usb


 There is a browse-able Git repository view here:

http://git.etherboot.org/people/balajirrao/gpxe.git/



The work appears to have stopped 8-21-2008 around 5:50 pm

From the log entries it appears he got support for OHCI and UHCI controllers working, and targeted specifically the USB network chipsets


Changing into the locally git clone repository and then into the src directory and typing the "make" command results in a stream of compilation messages including :


Which indicates [bin/usbcore.o][bin/urb.o][bin/uhci_hcd.o][bin/ohci_hcd.o] all cleanly compiled for gPXE. Those "appear" to be similarly named components for a USB bus support system under Linux recreated in a gPXE kernel environment.

Later [bin/asix.o] "appears" to be cleanly compiled


This entry suggests ASIX 88772 support might exist within the code

struct usb_driver asix_88772_usb_driver

This entry suggests he was using QEMU to start and test the code in a virtual machine and ran into some problems around 8-3-2008

[USB] Control transfers work properly as verified by qemu debugging messages. But its still qemu crashes for some reason.

This entry on 8-12-2008 suggests he got ohci code working

[USB] OHCI now works on bare metal.

This entry on 8-14-2008 suggests he got USB working

[USB] Kind of works..


from this we can [kind of] conclude he got it working.

It appears to me he based his design on the modular USB support developed for the Linux kernel and ported or re-implemented it in the gPXE kernel environment. Because of the mention of URBs I assume once he got the OHCI controller working, adding support for the UHCI support did not take much more effort (or he didn't have the hardware to test it).

Specifically it looks like he got an OHCI controller to work with possibly an ASIX AX88771 based USB network adapter after modifications to the OHCI and ASIX code.

Replicating his success, would be a good first step to broadening the support.

Another interesting tidbit:

Balaji seems to have documented using qemu to test gPXE.usb compilations here:

Using gPXE with QEMU
Build the gPXE from the instructions in the gPXE tarball. There will be a gpxe.usb file created in src/bin/ directory. That will be the USB image of the gPXE ROM which can be put into a bootable USB mass storage device. Now execute the following command
qemu -hda bin/gpxe.usb -net nic -net user -bootp http:/etherboot.org/gtest/gtest.gpxe
http://quark.entity.com/gtest/gtest.gpxe
represents where to download the kernel from using PXE
Qemu usb data snooping
While working on gPXE I had to snoop USB data for various reasons.
Here's how to do it.

QEMU

If your testing gPXE using QEMU, then your in luck. You can uncomment the lines starting with #define DEBUG_* in the QEMU source code and recompile. Now when you run QEMU, you get a tons of very valuable information from the console.
This will make QEMU run a bit slow. But who cares when they're debugging! The best thing about this approach is that the data being printed by QEMU is in a user readable format.

USBMON

This method is a bit involved. First you have to mount the debugfs in /sys/kernel/debug. Then change to the mounted directory into a directory called usbmon. There you'll see many files similar to 0t,0u,1t,1u,2t,2u etc. The files prefixed with a ‘u’ are supposed to provide output in a newer format. The number represents the kernel assigned USB bus number for a controller. The bus number your device is connected to can be obtained by running # lsusb.
Once you’ve found the bus you can (for example) ‘cat 3t’ to see tons of information of this form.
The format of the output is documented in a in text file located in the Linux Kernel Documentation/. You can also get it here.
This method is commonly used by device driver writers.
The device they're writing a driver for is connected from a Linux host via a pass-through-ed to a QEMU virtual machine. Then they run some OS like Windows in the QEMU virtual machine and when the windows driver interacts with the device, it can be snooped.
Examining the interactions, people reverse engineered Linux drivers from the behavior of the Windows drivers!

This is consistent with the git repo commit comments.

Another way is to mount the usbmon fs and then use Wireshark to treat the USB buses like network interfaces and "interpret" the USB traffic on the fly.

Sniffing USB Traffic - Different Approaches

usbmon captures

On my system, I do this:
modprobe usbmon
mount -t usbfs /dev/bus/usb /proc/bus/usb
After that, run "tshark -D" to list all the interfaces. You should see the usbmonX interfaces listed. You'll need to figure out which one is applicable to your device, but that shouldn't be too hard if you run "cat /proc/bus/usb/devices".
For example, if your device shows up as "Bus=04", then you need to capture using "tshark -i usbmon4". And of course, if you want to save the packets to a .pcap file, then you also need to specify "-w outfile".
You might also take a look at: http://wiki.wireshark.org/CaptureSetup/USB


Useful tips:

# modprobe asix
# modinfo asix | grep v0B95
# lsusb -t
# qemu -cdrom gpxe.iso -net nic
> CTRL-B
>gPXE config

(Interesting progress in testing the code)


So.. in VMware Player, Centos 5, running qemu virtual machine booting from the gPXE.iso with the ASIX driver (apparently) the code [does] recognize the ASIX AX88772A based USB-2-NIC adapter I had attached to my desktop, pass-through VMware to the Centos virtual machine, pass-through to qemu virtual machine and assigned to net0

# lsusb -t

Bus# 1
`-Dev# 1 Vendor 0x0000 Product 0x0000
  `-Dev#  2 Vendor 0x0b95 Product 0x772a

Red Hat 5 (Centos 5) appeared to have a problem loading gpxe.usb images so I used the gpxe.iso qemu cdrom option instead.

Also the qemu -device option wouldn't be available until a later version, so I used the -usbdevice option instead.

# qemu -cdrom gpxe.iso -net nic -net -user -usbdevice host:0b95:772a

really did not expect that to happen, it appears to initialize the USB controller and correctly identify the ASIX chipset and load that driver.

By re-routing the VMware connection to the host system, a Windows 7 desktop, I can confirm the MAC address for the ASIX USB-2-NIC adapter does indeed have that MAC Address


Next Day

centos already has usbmon built-into the kernel so # modprobe usbmon doesn't work, however simply mounting the debugfs does work, and you can cat 0t or 0u usb controller communications.

note to self: installing the vmware-tools and running the setup config makes handling gnome so much nicer, hello dynamic screen resolution

Wireshark did not get USB packet decode capability until version 1.2 the default yum repo for centos 5 only has wireshark 1.0, there don't appear to be repos that have it back ported or back compiled or back packaged.. but the source code is available. I saw a recommendation to us fedora 14 src packages for Wireshark 1.10 and that should compile.. maybe

# mkdir ws
# cd ws
# wget http://www.wireshark.org/download/src/all-versions/wireshark-1.2.0.tar.gz
# yum install gtk2-devel
# yum install libpcap-devel
# unpack the ws source
# ./configure
# make
# make install

Wireshark needs at least libpcap 1.0 to support usbmon, centos 5 only has libpcap 0.9

# mkdir lp
# cd lp
# wget http://www.tcpdump.org/release/libpcap-1.1.1.tar.gz
# tar -zxvf libpcap-1.1.1.tar.gz
# ./configure
# make
# make install

Recompile Wireshark to use the replacement libpcap  libraries

#cd ws
# make clean
# ./configure
# make
# make install

Coencidently Matt Cutts has nice article on 'Compiling a USB Program' with lots of how to references

http://www.mattcutts.com/blog/compile-a-simple-usb-program-in-linux/

Useful qemu options
http://doc.opensuse.org/products/draft/SLES/SLES-kvm_sd_draft/cha.qemu.running.html

Refined qemu start command [doesn't create a virtual pci nic to distract things]
# qemu -cdrom gpxe.iso -net none -usbdevice host:0b95:772a

# mount -t debugfs non_debugs /sys/kernel/debug
# /usr/local/bin/wireshark

Step by Step

Finally capturing and analyzing USB packet traffic 'Live'

So now I can start tweaking the code to see why it's not pulling a dhcp address.